Skip to main content

External Command - subprocess with advanced output processing

Project description

extcmd - subprocess with advanced output processing

This rather elaborate example shows a few interesting features of the library. Each line of the called command is passed to a Chain delegate, there are three copies made, the two first are just passed to another delegate while the last is modified with a Transform delegate. Finally all copies end up in our sink which is a composition of a simple Transform that prepends the stream name and a Redirect that, by default, just writes each line back to the corresponding stream.

Everything is encapsulated in a single module, extcmd:

>>> import extcmd
>>> import re

Create our sink object, it will simply write stuff back to the right stream while prepending the stream name to each line for easy inspection (and fun):

>>> sink = extcmd.Transform(lambda stream_name, line: "{0}: {1}".format(stream_name, line),
...                         extcmd.Redirect())
>>> better_subprocess = extcmd.ExternalCommandWithDelegate(
...     extcmd.Chain([
...         sink,  # pass one copy directly to the sink
...         sink,  # pass second copy directly to the sink
...         # transform a third copy with regular expression
...         extcmd.Transform(lambda stream_name, line: re.sub("hello", "bye", line, flags=re.I), sink),
...     ])
... )

After constructing that chain we can just call commands. As in subprocess there is also check_call() which raises an exception on failure:

>>> returncode = better_subprocess.call(['echo', 'Hello World'])
stdout: Hello World
stdout: Hello World
stdout: bye World

You can still look at returncode, it is returned from each call():

>>> returncode
0

The returncode is also passed to each delegate that supports the on_end() method

>>> class ReturnCode(extcmd.DelegateBase):
...     def on_end(self, returncode):
...         print "Return code is", returncode
>>> extcmd.ExternalCommandWithDelegate(ReturnCode()).call(['false'])
Return code is 1
1

Each started program is also passed to the on_start() method

>>> class VerboseStart(extcmd.DelegateBase):
...     def on_begin(self, args, kwargs):
...         print "Starting", args, kwargs
>>> extcmd.ExternalCommandWithDelegate(VerboseStart()).call(['true'])
Starting (['true'],) {}
0

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page