context

class invoke.context.Context(config=None)

Context-aware API wrapper & state-passing object.

Context objects are created during command-line parsing (or, if desired, by hand) and used to share parser and configuration state with executed tasks (see Aside: what exactly is this ‘context’ arg anyway?).

Specifically, the class offers wrappers for core API calls (such as run) which take into account CLI parser flags, configuration files, and/or changes made at runtime. It also acts as a proxy for its config attribute - see that attribute’s documentation for details.

Instances of Context may be shared between tasks when executing sub-tasks - either the same context the caller was given, or an altered copy thereof (or, theoretically, a brand new one).

New in version 1.0.

__init__(config=None)
Parameters:config

Config object to use as the base configuration.

Defaults to an anonymous/default Config instance.

cd(*args, **kwds)

Context manager that keeps directory state when executing commands.

Any calls to run, sudo, 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 the cwd property will also be affected by use of cd.

Like the actual ‘cd’ shell builtin, cd may be called with relative paths (keep in mind that your default starting directory is your user’s $HOME) and may be nested as well.

Below is a “normal” attempt at using the shell ‘cd’, which doesn’t work since all commands are executed in individual subprocesses – state is not kept between invocations of run or sudo:

c.run('cd /var/www')
c.run('ls')

The above snippet will list the contents of the user’s $HOME instead of /var/www. With cd, however, it will work as expected:

with c.cd('/var/www'):
    c.run('ls')  # Turns into "cd /var/www && ls"

Finally, a demonstration (see inline comments) of nesting:

with c.cd('/var/www'):
    c.run('ls') # cd /var/www && ls
    with c.cd('website1'):
        c.run('ls')  # cd /var/www/website1 && ls

Note

Space characters will be escaped automatically to make dealing with such directory names easier.

New in version 1.0.

command_cwds = None

A list of directories to ‘cd’ into before running commands with run or sudo; intended for management via cd, please see its docs for details.

command_prefixes = None

A list of commands to run (via “&&”) before the main argument to any run or sudo calls. Note that the primary API for manipulating this list is prefix; see its docs for details.

config

The fully merged Config object appropriate for this context.

Config settings (see their documentation for details) may be accessed like dictionary keys (c.config['foo']) or object attributes (c.config.foo).

As a convenience shorthand, the Context object proxies to its config attribute in the same way - e.g. c['foo'] or c.foo returns the same value as c.config['foo'].

cwd

Return the current working directory, accounting for uses of cd.

New in version 1.0.

prefix(*args, **kwds)

Prefix all nested run/sudo commands with given command plus &&.

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 c.prefix('workon myvenv'):
    c.run('./manage.py migrate')

In the above snippet, the actual shell command run would be this:

$ workon myvenv && ./manage.py migrate

This context manager is compatible with cd, so if your virtualenv doesn’t cd in its postactivate script, you could do the following:

with c.cd('/path/to/app'):
    with c.prefix('workon myvenv'):
        c.run('./manage.py migrate')
        c.run('./manage.py loaddata fixture')

Which would result in executions like so:

$ cd /path/to/app && workon myvenv && ./manage.py migrate
$ cd /path/to/app && workon myvenv && ./manage.py loaddata fixture

Finally, as alluded to above, prefix may be nested if desired, e.g.:

with c.prefix('workon myenv'):
    c.run('ls')
    with c.prefix('source /some/script'):
        c.run('touch a_file')

The result:

$ workon myenv && ls
$ workon myenv && source /some/script && touch a_file

Contrived, but hopefully illustrative.

New in version 1.0.

run(command, **kwargs)

Execute a local shell command, honoring config options.

Specifically, this method instantiates a Runner subclass (according to the runner config option; default is Local) and calls its .run method with command and kwargs.

See Runner.run for details on command and the available keyword arguments.

New in version 1.0.

sudo(command, **kwargs)

Execute a shell command, via sudo.

Basics

In general, this method is identical to run, but adds a handful of convenient behaviors around invoking the sudo program. It doesn’t do anything users could not do themselves by wrapping run, but the use case is too common to make users reinvent these wheels themselves.

Specifically, sudo:

  • Places a FailingResponder into the watchers kwarg (see Automatically responding to program output) which:

    • searches for the configured sudo password prompt;
    • responds with the configured sudo password (sudo.password from the configuration);
    • can tell when that response causes an authentication failure (e.g. if the system requires a password and one was not configured), and raises AuthFailure if so.
  • Builds a sudo command string using the supplied command argument, prefixed by various flags (see below);

  • Executes that command via a call to run, returning the result.

Flags used

sudo flags used under the hood include:

  • -S to allow auto-responding of password via stdin;
  • -p <prompt> to explicitly state the prompt to use, so we can be sure our auto-responder knows what to look for;
  • -u <user> if user is not None, to execute the command as a user other than root;
  • When -u is present, -H is also added, to ensure the subprocess has the requested user’s $HOME set properly.

Configuring behavior

There are a couple of ways to change how this method behaves:

  • Because it wraps run, it honors all run config parameters and keyword arguments, in the same way that run does.

    • Thus, invocations such as c.sudo('command', echo=True) are possible, and if a config layer (such as a config file or env var) specifies that e.g. run.warn = True, that too will take effect under sudo.
  • sudo has its own set of keyword arguments (see below) and they are also all controllable via the configuration system, under the sudo.* tree.

    • Thus you could, for example, pre-set a sudo user in a config file; such as an invoke.json containing {"sudo": {"user": "someuser"}}.
Parameters:
  • password (str) – Runtime override for sudo.password.
  • user (str) – Runtime override for sudo.user.

New in version 1.0.

class invoke.context.MockContext(config=None, **kwargs)

A Context whose methods’ return values can be predetermined.

Primarily useful for testing Invoke-using codebases.

Note

Methods not given Results to yield will raise NotImplementedError if called (since the alternative is to call the real underlying method - typically undesirable when mocking.)

New in version 1.0.

__init__(config=None, **kwargs)

Create a Context-like object whose methods yield Result objects.

Parameters:
  • config – A Configuration object to use. Identical in behavior to Context.
  • run

    A data structure of Results, to return from calls to the instantiated object’s run method (instead of actually executing the requested shell command).

    Specifically, this kwarg accepts:

    • A single Result object, which will be returned once.
    • An iterable of Results, which will be returned on each subsequent call to .run.
    • A map of command strings to either of the above, allowing specific call-and-response semantics instead of assuming a call order.
  • sudo – Identical to run, but whose values are yielded from calls to sudo.
Raises:

TypeError, if the values given to run or other kwargs aren’t individual Result objects or iterables.

set_result_for(attname, command, result)

Modify the stored mock results for given attname (e.g. run).

This is similar to how one instantiates MockContext with a run or sudo dict kwarg. For example, this:

mc = MockContext(run={'mycommand': Result("mystdout")})
assert mc.run('mycommand').stdout == "mystdout"

is functionally equivalent to this:

mc = MockContext()
mc.set_result_for('run', 'mycommand', Result("mystdout"))
assert mc.run('mycommand').stdout == "mystdout"

set_result_for is mostly useful for modifying an already-instantiated MockContext, such as one created by test setup or helper methods.

New in version 1.0.