Context Managers¶
Context managers for use with the with
statement.
Note
When using Python 2.5, you will need to start your fabfile
with from __future__ import with_statement
in order to make use of
the with
statement (which is a regular, non __future__
feature of
Python 2.6+.)
Note
If you are using multiple directly nested with
statements, it can
be convenient to use multiple context expressions in one single with
statement. Instead of writing:
with cd('/path/to/app'):
with prefix('workon myvenv'):
run('./manage.py syncdb')
run('./manage.py loaddata myfixture')
you can write:
with cd('/path/to/app'), prefix('workon myvenv'):
run('./manage.py syncdb')
run('./manage.py loaddata myfixture')
Note that you need Python 2.7+ for this to work. On Python 2.5 or 2.6, you can do the following:
from contextlib import nested
with nested(cd('/path/to/app'), prefix('workon myvenv')):
...
Finally, note that settings
implements
nested
itself – see its API doc for details.
-
fabric.context_managers.
cd
(path)¶ Context manager that keeps directory state when calling remote operations.
Any calls to
run
,sudo
,get
, orput
within the wrapped block will implicitly have a string similar to"cd <path> && "
prefixed in order to give the sense that there is actually statefulness involved.Because use of
cd
affects all such invocations, any code making use of those operations, such as much of thecontrib
section, will also be affected by use ofcd
.Like the actual ‘cd’ shell builtin,
cd
may be called with relative paths (keep in mind that your default starting directory is your remote user’s$HOME
) and may be nested as well.Below is a “normal” attempt at using the shell ‘cd’, which doesn’t work due to how shell-less SSH connections are implemented – state is not kept between invocations of
run
orsudo
:run('cd /var/www') run('ls')
The above snippet will list the contents of the remote user’s
$HOME
instead of/var/www
. Withcd
, however, it will work as expected:with cd('/var/www'): run('ls') # Turns into "cd /var/www && ls"
Finally, a demonstration (see inline comments) of nesting:
with cd('/var/www'): run('ls') # cd /var/www && ls with cd('website1'): run('ls') # cd /var/www/website1 && ls
Note
This context manager is currently implemented by appending to (and, as always, restoring afterwards) the current value of an environment variable,
env.cwd
. However, this implementation may change in the future, so we do not recommend manually alteringenv.cwd
– only the behavior ofcd
will have any guarantee of backwards compatibility.Note
Space characters will be escaped automatically to make dealing with such directory names easier.
Changed in version 1.0: Applies to
get
andput
in addition to the command-running operations.See also
-
fabric.context_managers.
char_buffered
(*args, **kwds)¶ Force local terminal
pipe
be character, not line, buffered.Only applies on Unix-based systems; on Windows this is a no-op.
-
fabric.context_managers.
hide
(*args, **kwds)¶ Context manager for setting the given output
groups
to False.groups
must be one or more strings naming the output groups defined inoutput
. The given groups will be set to False for the duration of the enclosed block, and restored to their previous value afterwards.For example, to hide the “[hostname] run:” status lines, as well as preventing printout of stdout and stderr, one might use
hide
as follows:def my_task(): with hide('running', 'stdout', 'stderr'): run('ls /var/www')
-
fabric.context_managers.
lcd
(path)¶ Context manager for updating local current working directory.
This context manager is identical to
cd
, except that it changes a different env var (lcwd
, instead ofcwd
) and thus only affects the invocation oflocal
and the local arguments toget
/put
.Relative path arguments are relative to the local user’s current working directory, which will vary depending on where Fabric (or Fabric-using code) was invoked. You can check what this is with os.getcwd. It may be useful to pin things relative to the location of the fabfile in use, which may be found in env.real_fabfile
New in version 1.0.
-
fabric.context_managers.
path
(path, behavior='append')¶ Append the given
path
to the PATH used to execute any wrapped commands.Any calls to
run
orsudo
within the wrapped block will implicitly have a string similar to"PATH=$PATH:<path> "
prepended before the given command.You may customize the behavior of
path
by specifying the optionalbehavior
keyword argument, as follows:'append'
: append given path to the current$PATH
, e.g.PATH=$PATH:<path>
. This is the default behavior.'prepend'
: prepend given path to the current$PATH
, e.g.PATH=<path>:$PATH
.'replace'
: ignore previous value of$PATH
altogether, e.g.PATH=<path>
.
Note
This context manager is currently implemented by modifying (and, as always, restoring afterwards) the current value of environment variables,
env.path
andenv.path_behavior
. However, this implementation may change in the future, so we do not recommend manually altering them directly.New in version 1.0.
-
fabric.context_managers.
prefix
(command)¶ Prefix all wrapped
run
/sudo
commands with given command plus&&
.This is nearly identical to
cd
, except that nested invocations append to a list of command strings instead of modifying a single string.Most of the time, you’ll want to be using this alongside a shell script which alters shell state, such as ones which export or alter shell environment variables.
For example, one of the most common uses of this tool is with the
workon
command from virtualenvwrapper:with prefix('workon myvenv'): run('./manage.py syncdb')
In the above snippet, the actual shell command run would be this:
$ workon myvenv && ./manage.py syncdb
This context manager is compatible with
cd
, so if your virtualenv doesn’tcd
in itspostactivate
script, you could do the following:with cd('/path/to/app'): with prefix('workon myvenv'): run('./manage.py syncdb') run('./manage.py loaddata myfixture')
Which would result in executions like so:
$ cd /path/to/app && workon myvenv && ./manage.py syncdb $ cd /path/to/app && workon myvenv && ./manage.py loaddata myfixture
Finally, as alluded to near the beginning,
prefix
may be nested if desired, e.g.:with prefix('workon myenv'): run('ls') with prefix('source /some/script'): run('touch a_file')
The result:
$ workon myenv && ls $ workon myenv && source /some/script && touch a_file
Contrived, but hopefully illustrative.
-
fabric.context_managers.
quiet
()¶ Alias to
settings(hide('everything'), warn_only=True)
.Useful for wrapping remote interrogative commands which you expect to fail occasionally, and/or which you want to silence.
Example:
with quiet(): have_build_dir = run("test -e /tmp/build").succeeded
When used in a task, the above snippet will not produce any
run: test -e /tmp/build
line, nor will any stdout/stderr display, and command failure is ignored.See also
New in version 1.5.
-
fabric.context_managers.
remote_tunnel
(*args, **kwds)¶ Create a tunnel forwarding a locally-visible port to the remote target.
For example, you can let the remote host access a database that is installed on the client host:
# Map localhost:6379 on the server to localhost:6379 on the client, # so that the remote 'redis-cli' program ends up speaking to the local # redis-server. with remote_tunnel(6379): run("redis-cli -i")
The database might be installed on a client only reachable from the client host (as opposed to on the client itself):
# Map localhost:6379 on the server to redis.internal:6379 on the client with remote_tunnel(6379, local_host="redis.internal") run("redis-cli -i")
remote_tunnel
accepts up to four arguments:remote_port
(mandatory) is the remote port to listen to.local_port
(optional) is the local port to connect to; the default is the same port as the remote one.local_host
(optional) is the locally-reachable computer (DNS name or IP address) to connect to; the default islocalhost
(that is, the same computer Fabric is running on).remote_bind_address
(optional) is the remote IP address to bind to for listening, on the current target. It should be an IP address assigned to an interface on the target (or a DNS name that resolves to such IP). You can use “0.0.0.0” to bind to all interfaces.
Note
By default, most SSH servers only allow remote tunnels to listen to the localhost interface (127.0.0.1). In these cases,
remote_bind_address
is ignored by the server, and the tunnel will listen only to 127.0.0.1.
-
fabric.context_managers.
settings
(*args, **kwargs)¶ Nest context managers and/or override
env
variables.settings
serves two purposes:Most usefully, it allows temporary overriding/updating of
env
with any provided keyword arguments, e.g.with settings(user='foo'):
. Original values, if any, will be restored once thewith
block closes.- The keyword argument
clean_revert
has special meaning forsettings
itself (see below) and will be stripped out before execution.
- The keyword argument
In addition, it will use contextlib.nested to nest any given non-keyword arguments, which should be other context managers, e.g.
with settings(hide('stderr'), show('stdout')):
.
These behaviors may be specified at the same time if desired. An example will hopefully illustrate why this is considered useful:
def my_task(): with settings( hide('warnings', 'running', 'stdout', 'stderr'), warn_only=True ): if run('ls /etc/lsb-release'): return 'Ubuntu' elif run('ls /etc/redhat-release'): return 'RedHat'
The above task executes a
run
statement, but will warn instead of aborting if thels
fails, and all output – including the warning itself – is prevented from printing to the user. The end result, in this scenario, is a completely silent task that allows the caller to figure out what type of system the remote host is, without incurring the handful of output that would normally occur.Thus,
settings
may be used to set any combination of environment variables in tandem with hiding (or showing) specific levels of output, or in tandem with any other piece of Fabric functionality implemented as a context manager.If
clean_revert
is set toTrue
,settings
will not revert keys which are altered within the nested block, instead only reverting keys whose values remain the same as those given. More examples will make this clear; below is howsettings
operates normally:# Before the block, env.parallel defaults to False, host_string to None with settings(parallel=True, host_string='myhost'): # env.parallel is True # env.host_string is 'myhost' env.host_string = 'otherhost' # env.host_string is now 'otherhost' # Outside the block: # * env.parallel is False again # * env.host_string is None again
The internal modification of
env.host_string
is nullified – not always desirable. That’s whereclean_revert
comes in:# Before the block, env.parallel defaults to False, host_string to None with settings(parallel=True, host_string='myhost', clean_revert=True): # env.parallel is True # env.host_string is 'myhost' env.host_string = 'otherhost' # env.host_string is now 'otherhost' # Outside the block: # * env.parallel is False again # * env.host_string remains 'otherhost'
Brand new keys which did not exist in
env
prior to usingsettings
are also preserved ifclean_revert
is active. WhenFalse
, such keys are removed when the block exits.New in version 1.4.1: The
clean_revert
kwarg.
-
fabric.context_managers.
shell_env
(**kw)¶ Set shell environment variables for wrapped commands.
For example, the below shows how you might set a ZeroMQ related environment variable when installing a Python ZMQ library:
with shell_env(ZMQ_DIR='/home/user/local'): run('pip install pyzmq')
As with
prefix
, this effectively turns therun
command into:$ export ZMQ_DIR='/home/user/local' && pip install pyzmq
Multiple key-value pairs may be given simultaneously.
Note
If used to affect the behavior of
local
when running from a Windows localhost,SET
commands will be used to implement this feature.
-
fabric.context_managers.
show
(*args, **kwds)¶ Context manager for setting the given output
groups
to True.groups
must be one or more strings naming the output groups defined inoutput
. The given groups will be set to True for the duration of the enclosed block, and restored to their previous value afterwards.For example, to turn on debug output (which is typically off by default):
def my_task(): with show('debug'): run('ls /var/www')
As almost all output groups are displayed by default,
show
is most useful for turning on the normally-hiddendebug
group, or when you know or suspect that code calling your own code is trying to hide output withhide
.
-
fabric.context_managers.
warn_only
()¶ Alias to
settings(warn_only=True)
.See also