Usage¶
Installation¶
From cheeseshop¶
pip install spm
From source¶
git clone git://github.com/acatton/python-spm spm
pip install -e ./spm
Learn by example¶
You can reduce spm to two function run()
and pipe()
. But the objects
returned by these two functions have many useful methods.
Run subcommands¶
>>> stdout, stderr = run('echo', 'Hello, World').wait()
>>> stdout
'Hello, World\n'
>>> stdout, stderr = run('false').wait()
Traceback (most recent call last):
...
subprocess.CalledProcessError: Command 'false' returned non-zero exit status 1
run()
create a subprocess, but it doesn’t spawn it yet. wait()
spawn is
one way to spawn the said subprocess.
You can also read its output:
>>> run('echo', 'Hello, World').stdout.read()
'Hello, World\n'
Pipe subprocesses together¶
Piping is done with pipe()
.
pipe()
accepts either an argument list or a Subprocess
. pipe()
is
also a method on Subprocess
.
>>> data, _ = pipe(['echo', '-n', 'Hello World'], ['bzip2']).wait()
>>> import bz2
>>> bz2.decompress(data)
'Hello World'
Redirect output to a file¶
You can set Subprocess.stdout
to an open file. spm
will be in charge of
closing it.
>>> proc = run('echo', 'Hello World')
>>> import os
>>> proc.stdout = open(os.devnull, 'w')
>>> proc.wait()
(None, None)
Propagate the environment¶
You can use the keyword argument env
on run()
or pipe()
in order to
override some variable in the environment of the subprocess.
>>> run('env').stdout.read()
''
>>> run('env', env={'FOO': 'BAR'}).stdout.read()
'FOO=BAR\n'
For security reasons, the environment doesn’t get propagated to the subprocess. See Environment propagation opt-in.
The class propagate_env
(but you should think of it as a function) will
propagate the environment, and update it if you pass it
>>> run('env', env=propagate_env()).stdout.read().decode() != ''
True
>>> 'a=b' in run('env', env=propagate_env(a='b')).stdout.read().split('\n')
True
>>> 'FOO=BAR' in run('env', env=propagate_env({'FOO': 'BAR'})).stdout.read().split('\n')
True
Debug your subprocesses¶
You can debug your subprocesses and try to running manually by getting their representation or converting them to strings.
Copying and pasting the string in your terminal should have exact the same
result than calling wait()
.
>>> print(run('echo', 'Hello'))
env - echo Hello
>>> print(run('echo', 'Hello, World'))
env - echo 'Hello, World'
>>> run('echo', '$NAME')
<Subprocess "env - echo '$NAME'">
Create command functions¶
You can also create a git()
function if you wanted. This could be done
thanks to functools.partial()
.
>>> from functools import partial
>>> git = partial(run, 'git')
>>> git('commit')
<Subprocess 'env - git commit'>
>>> git('archive', '--output=/tmp/archive.tar.gz')
<Subprocess 'env - git archive --output=/tmp/archive.tar.gz'>
API¶
-
class
spm.
Subprocess
(args, env=None)¶ Subprocess object used to access properties of the subprocess such as its returncode.
You shouldn’t have to instantiate this class.
run()
andpipe()
will do it for you.-
pipe
(*args, **kwargs)¶ Pipe processes together. pipe() can receive an argument list or a subprocess.
>>> print(run('echo', 'foo\nbar').pipe('grep', 'bar').stdout.read() ... .decode()) bar >>> noop = run('gzip').pipe('zcat') >>> print(noop) env - gzip | env - zcat >>> # This will be: echo -n foo | gzip | zcat >>> print(run('echo', '-n', 'foo').pipe(noop).stdout.read() ... .decode()) foo
-
returncode
¶ Return the the returncode of the subprocess. If the subprocess isn’t terminated yet, it will return
None
.
-
stdin
¶ Set the stdin of the subprocess. It should be a file. If its
None
it will be a pipe to wich you can write from the main process.
-
stdout
¶ Set the stdout of the subprocess. It should be a file. If its
None
it could be read from the main process.
-
wait
()¶ Waits for the subprocess to finish, and then return a tuple of its stdout and stderr.
If there’s no error, the stderr is
None
. If the process fails (has a non-zero exit code) it raises asubprocess.CalledProcessError
.
-
-
spm.
run
(*args, **kwargs)¶ Run a simple subcommand:
>>> print(run('echo', '-n', 'hello world').stdout.read().decode()) hello world
Returns a Subprocess.
-
spm.
pipe
(cmd, *arguments, **kwargs)¶ Pipe many commands:
>>> noop = pipe(['gzip'], ['gzip'], ['zcat'], ['zcat']) >>> _ = noop.stdin.write('foo'.encode()) # Ignore output in Python 3 >>> noop.stdin.close() >>> print(noop.stdout.read().decode()) foo
Returns a Subprocess.