camayoc.command module

Execute local or remote commands.

class camayoc.command.Command(system, response_handler=None)[source]

Bases: object

A convenience class for working with local or remote commands.

This class provides the ability to execute shell commands on either the local system or a remote system. Here is a pedagogic usage example:

>>> from camayoc import command
>>> system = command.System(hostname='localhost', transport='local')
>>> cmd = command.Command(system)
>>> response = cmd.run(('echo', '-n', 'foo'))
>>> response.returncode == 0
True
>>> response.stdout == 'foo'
True
>>> response.stderr == ''
True

The above example shows how various classes fit together. It’s also verbose: smartly chosen defaults mean that most real code is much more concise.

You can customize how Command objects execute commands and handle responses by fiddling with the two public instance attributes:

machine
A Plumbum machine. run() delegates all command execution responsibilities to this object.
response_handler
A callback function. Each time machine executes a command, the result is handed to this callback, and the callback’s return value is handed to the user.

If system.transport is local or ssh, machine will be set so that commands run locally or over SSH, respectively. If system.transport is None, the constructor will guess how to set machine by comparing the hostname embedded in system.hostname against the current system’s hostname. If they match, machine is set to execute commands locally; and vice versa.

Parameters:
run(args, **kwargs)[source]

Run a command and return self.response_handler(result).

This method is a thin wrapper around Plumbum’s BaseCommand.run method, which is itself a thin wrapper around the standard library’s subprocess.Popen class. See their documentation for detailed usage instructions. See camayoc.command.Command for a usage example.

class camayoc.command.CompletedProcess(args, returncode, stdout, stderr)[source]

Bases: object

A process that has finished running.

This class is similar to the subprocess.CompletedProcess class available in Python 3.5 and above. Significant differences include the following:

  • All constructor arguments are required.
  • check_returncode() returns a custom exception, not subprocess.CalledProcessError.

All constructor arguments are stored as instance attributes.

Parameters:
  • args – A string or a sequence. The arguments passed to camayoc.command.Command.run().
  • returncode – The integer exit code of the executed process. Negative for signals.
  • stdout – The standard output of the executed process.
  • stderr – The standard error of the executed process.
check_returncode()[source]

Raise an exception if returncode is non-zero.

Raise camayoc.exceptions.CalledProcessError if returncode is non-zero.

Why not raise subprocess.CalledProcessError? Because stdout and stderr are not included when str() is called on a CalledProcessError object. A typical message is:

"Command '('ls', 'foo')' returned non-zero exit status 2"

This information is valuable. One could still make subprocess.CalledProcessError work by overloading args:

>>> if isinstance(args, (str, bytes)):
...     custom_args = (args, stdout, stderr)
... else:
...     custom_args = tuple(args) + (stdout, stderr)
>>> subprocess.CalledProcessError(args, returncode)

But this seems like a hack.

In addition, it’s generally good for an application to raise expected exceptions from its own namespace, so as to better abstract away dependencies.

class camayoc.command.System(hostname, transport)

Bases: tuple

A system representation to run commands on.

hostname

Alias for field number 0

transport

Alias for field number 1

camayoc.command.code_handler(completed_proc)[source]

Check the process for a non-zero return code. Return the process.

Check the return code by calling completed_proc.check_returncode(). See: camayoc.command.CompletedProcess.check_returncode().

camayoc.command.echo_handler(completed_proc)[source]

Immediately return completed_proc.