wizard.shell

Wrappers around subprocess functionality that simulate an actual shell.

Classes

class wizard.shell.Shell(dry=False)

An advanced shell that performs logging. If dry is True, no commands are actually run.

call(*args, **kwargs)

Performs a system call. The actual executable and options should be passed as arguments to this function. It will magically ensure that ‘wizard’ as a command works. Several keyword arguments are also supported:

Parameters:
  • python – explicitly marks the subprocess as Python or not Python for improved error reporting. By default, we use is_python() to autodetect this.
  • input – input to feed the subprocess on standard input.
  • interactive – whether or not directly hook up all pipes to the controlling terminal, to allow interaction with subprocess.
  • strip – if True, instead of returning a tuple, return the string stdout output of the command with trailing newlines removed. This emulates the behavior of backticks and $() in Bash. Prefer to use eval() instead (you should only need to explicitly specify this if you are using another wrapper around this function).
  • log – if True, we log the call as INFO, if False, we log the call as DEBUG, otherwise, we detect based on strip.
  • stdout
  • stderr
  • stdin – a file-type object that will be written to or read from as a pipe.
Returns:

a tuple of strings (stdout, stderr), or a string stdout if strip is specified.

>>> sh = Shell()
>>> sh.call("echo", "Foobar")
('Foobar\n', '')
>>> sh.call("cat", input='Foobar')
('Foobar', '')
callAsUser(*args, **kwargs)

Performs a system call as a different user. This is only possible if you are running as root. Keyword arguments are the same as call() with the following additions:

Parameters:
  • user – name of the user to run command as.
  • uid – uid of the user to run command as.

Note

The resulting system call internally uses sudo, and as such environment variables will get scrubbed. We manually preserve SSH_GSSAPI_NAME.

eval(*args, **kwargs)

Evaluates a command and returns its output, with trailing newlines stripped (like backticks in Bash). This is a convenience method for calling call() with strip.

>>> sh = Shell()
>>> sh.eval("echo", "Foobar") 
'Foobar'
safeCall(*args, **kwargs)

Checks if the owner of the current working directory is the same as the current user, and if it isn’t, attempts to sudo to be that user. The intended use case is for calling Git commands when running as root, but this method should be used when interfacing with any moderately complex program that depends on working directory context. Keyword arguments are the same as call().

setcwd(cwd)

Sets the directory processes are executed in. This sets a value to be passed as the cwd argument to subprocess.Popen.

class wizard.shell.ParallelShell(dry=False, max=10)

Modifies the semantics of Shell so that commands are queued here, and executed in parallel using waitpid with max subprocesses, and result in callback execution when they finish.

call(*args, **kwargs)

Enqueues a system call for parallel processing. If there are no openings in the queue, this will block. Keyword arguments are the same as Shell.call() with the following additions:

Parameters:
  • on_success – Callback function for success (zero exit status). The callback function should accept two arguments, stdout and stderr.
  • on_error – Callback function for failure (nonzero exit status). The callback function should accept one argument, the exception that would have been thrown by the synchronous version.
Returns:

The subprocess.Proc object that was opened.

callAsUser(*args, **kwargs)

Enqueues a system call under a different user for parallel processing. Keyword arguments are the same as Shell.callAsUser() with the additions of keyword arguments from call().

safeCall(*args, **kwargs)

Enqueues a “safe” call for parallel processing. Keyword arguments are the same as Shell.safeCall() with the additions of keyword arguments from call().

eval(*args, **kwargs)

No difference from call(). Consider having a non-parallel shell if the program you are shelling out to is fast.

join()

Waits for all of our subprocesses to terminate.

static make(no_parallelize, max)

Convenience method oriented towards command modules.

reap(pid, status)

Reaps a process.

class wizard.shell.DummyParallelShell(dry=False)

Bases: wizard.shell.ParallelShell

Same API as ParallelShell, but doesn’t actually parallelize (i.e. all calls to wait() block.)

call(*args, **kwargs)

Performs a system call. The actual executable and options should be passed as arguments to this function. It will magically ensure that ‘wizard’ as a command works. Several keyword arguments are also supported:

Parameters:
  • python – explicitly marks the subprocess as Python or not Python for improved error reporting. By default, we use is_python() to autodetect this.
  • input – input to feed the subprocess on standard input.
  • interactive – whether or not directly hook up all pipes to the controlling terminal, to allow interaction with subprocess.
  • strip – if True, instead of returning a tuple, return the string stdout output of the command with trailing newlines removed. This emulates the behavior of backticks and $() in Bash. Prefer to use eval() instead (you should only need to explicitly specify this if you are using another wrapper around this function).
  • log – if True, we log the call as INFO, if False, we log the call as DEBUG, otherwise, we detect based on strip.
  • stdout
  • stderr
  • stdin – a file-type object that will be written to or read from as a pipe.
Returns:

a tuple of strings (stdout, stderr), or a string stdout if strip is specified.

>>> sh = Shell()
>>> sh.call("echo", "Foobar")
('Foobar\n', '')
>>> sh.call("cat", input='Foobar')
('Foobar', '')
callAsUser(*args, **kwargs)

Performs a system call as a different user. This is only possible if you are running as root. Keyword arguments are the same as call() with the following additions:

Parameters:
  • user – name of the user to run command as.
  • uid – uid of the user to run command as.

Note

The resulting system call internally uses sudo, and as such environment variables will get scrubbed. We manually preserve SSH_GSSAPI_NAME.

eval(*args, **kwargs)

Evaluates a command and returns its output, with trailing newlines stripped (like backticks in Bash). This is a convenience method for calling call() with strip.

>>> sh = Shell()
>>> sh.eval("echo", "Foobar") 
'Foobar'
join()

Waits for all of our subprocesses to terminate.

static make(no_parallelize, max)

Convenience method oriented towards command modules.

reap(pid, status)

Reaps a process.

safeCall(*args, **kwargs)

Checks if the owner of the current working directory is the same as the current user, and if it isn’t, attempts to sudo to be that user. The intended use case is for calling Git commands when running as root, but this method should be used when interfacing with any moderately complex program that depends on working directory context. Keyword arguments are the same as call().

setcwd(cwd)

Sets the directory processes are executed in. This sets a value to be passed as the cwd argument to subprocess.Popen.

Functions

wizard.shell.is_python(args)

Detects whether or not an argument list invokes a Python program.

wizard.shell.drop_priviledges(dir, log_file)

Checks if we are running as root. If we are, attempt to drop priviledges to the user who owns dir, by re-calling itself using sudo with exec, such that the new process subsumes our current one. If log_file is passed, the file is chown’ed to the user we are dropping priviledges to, so the subprocess can write to it.

Data

wizard.shell.wizard_bin

This is the path to the wizard executable as specified by the caller; it lets us recursively invoke wizard.

Exceptions

exception wizard.shell.Error

Base exception for this module

exception wizard.shell.CallError(code, args, stdout, stderr)

Indicates that a subprocess call returned a nonzero exit status.

args

List of the program and arguments that failed.

code

The exit code of the failed subprocess.

stderr

The stderr of the program.

stdout

The stdout of the program.

exception wizard.shell.PythonCallError(code, args, stdout, stderr)

Bases: wizard.shell.CallError

Indicates that a Python subprocess call had an uncaught exception. This exception also contains the attributes of CallError.

name

Name of the uncaught exception.

Table Of Contents

Previous topic

wizard.resolve

Next topic

wizard.sql

This Page