Normally Fabric quits as soon as a run() call returns a non-zero exit code. For some calls, however, this is expected. For example, PNGOut returns an error code of 2 when it is unable to compress a file.
Currently I can only circumvent this limitation by either using shell logic (do_something_that_fails || true
or do_something_that_fails || do_something_else
), but I'd rather be able to keep my logic in plain Python (as is the Fabric promise).
Is there a way to check for an error code and react to it rather than having Fabric panic and die? I still want the default behaviours for other calls, so changing its behaviour by modifying the environment doesn't seem like a good option (and as far as I recall, you can only use that to tell it to warn instead of dying anyway).
You can prevent aborting on non-zero exit codes by using the settings
context manager and the warn_only
setting:
from fabric.api import settings
with settings(warn_only=True):
result = run('pngout old.png new.png')
if result.return_code == 0:
do something
elif result.return_code == 2:
do something else
else: #print error to user
print result
raise SystemExit()
Update: My answer is outdated. See comments below.
Yes, you can. Just change the environment's abort_exception
. For example:
from fabric.api import settings
class FabricException(Exception):
pass
with settings(abort_exception = FabricException):
try:
run(<something that might fail>)
except FabricException:
<handle the exception>
The documentation on abort_exception
is here.
Apparently messing with the environment is the answer.
fabric.api.settings
can be used as a context manager (with with
) to apply it to individual statements. The return value of run()
, local()
and sudo()
calls isn't just the output of the shell command, but also has special properties (return_code
and failed
) that allow reacting to the errors.
I guess I was looking for something closer to the behaviour of subprocess.Popen
or Python's usual exception handling.
try this
from fabric.api import run, env
env.warn_only = True # if you want to ignore exceptions and handle them yurself
command = "your command"
x = run(command, capture=True) # run or local or sudo
if(x.stderr != ""):
error = "On %s: %s" %(command, x.stderr)
print error
print x.return_code # which may be 1 or 2
# do what you want or
raise Exception(error) #optional
else:
print "the output of %s is: %s" %(command, x)
print x.return_code # which is 0