runs has improved versions of call(), check_call(), check_output(), and run() from Python's subprocess module that handle multiple commands and blocks of text, fix some defects, and add some features.
import runs runs(''' ls df -k # or perhaps -h? echo 'Done and done' ''')---
subprocess is essential but:
- You can only run one command at a time
- Commands to subprocess must be either a sequence of strings or a string, depending on whether
shell=Trueor not - Results are returned by default as bytes and not strings
---
The runs functions let you run a block of text as a sequence of subprocess calls.
runs provides call-compatible replacements for the functions subprocess.call(), subprocess.check_call(), subprocess.check_output(), and subprocess.run()
Each replacement function takes a block of text, which is split into individual command lines, or a list of commands, and returns a list of values, one for each command. A block of text can contain line continuations, and comments, which are ignored.
The replacement functions also add optional logging, error handling, and lazy evaluation, and use UTF-8 encoding by default.
The module runs is callable - runs() is a synonym for runs.run().
EXAMPLES:
# ``runs()`` or ``runs.run()`` writes to stdout and stderr just as if you'd run # the commands from the terminal import runs runs('echo "hello, world!"') # prints hello, world! # runs.check_output() returns a list, one string result for each command results = check_output(''' echo line one # Here's line one. echo 'line " two "' # and two! ''') assert results == ['line one', 'line " two "'] # Line continuations work too, either single or double runs(''' ls -cail # One command that takes many lines. g++ -DDEBUG -O0 -g -std=c++17 -pthread -I ./include -lm -lstdc++ \ -Wall -Wextra -Wno-strict-aliasing -Wpedantic \\ -MMD -MP -MF -c src/tests.cpp -o build/./src/tests.cpp.o echo DONE ''')NOTES:
Exactly like subprocess, runs differs from the shell in a few ways, so you can't just paste your shell scripts in:
- Redirection doesn't work.
result = runs.check_output('echo foo > bar.txt') assert result == ['foo > bar.txt\n']- Pipes don't work.
result = runs.check_output('echo foo | wc') assert result == ['foo | wc \n']- Environment variables are not expanded in command lines
result = runs.check_output('echo $FOO', env={'FOO': 'bah!'}) assert result == ['$FOO\n']Environment variables are exported to the subprocess, absolutely, but no environment variable expension happens on command lines.
runs( commands, *args, iterate=False, encoding='utf8', on_exception=None, echo=False, **kwargs, )Call subprocess.run() on each command. Return a list of subprocess.CompletedProcess instances. See the help for subprocess.run() for more information.
- Arguments:
- commands:
- A string, which gets split into lines on line endings, or a list of strings.
- args:
- Positional arguments to
subprocess.run()(but prefer keyword arguments!) - on_exception:
If
on_exceptionisFalse, the default, exceptions fromsubprocess.run()are raised as usual.If
on_exceptionis True, they are ignored.If
on_exceptionis a callable, the line that caused the exception is passed to it.If
on_exceptionis a string, the line causing the exception is printed, prefixed with that string.- echo:
- If
echoisFalse, the default, then commands are silently executed. IfechoisTrue, commands are printed prefixed with$Ifechois a string, commands are printed prefixed with that string Ifechois callable, then each command is passed to it. - iterate:
If
iterateisFalse, the default, then a list of results is returned.Otherwise an iterator of results which is returned, allowing for lazy evaluation.
- encoding:
- Like the argument to
subprocess.run(), except the default is'utf8' - kwargs:
- Named arguments passed on to
subprocess.run()
runs.call( commands, *args, iterate=False, encoding='utf8', on_exception=None, echo=False, **kwargs, )Call subprocess.call() on each command. Return a list of integer returncodes, one for each command executed. See the help for subprocess.call() for more information.
- Arguments:
- commands:
- A string, which gets split into lines on line endings, or a list of strings.
- args:
- Positional arguments to
subprocess.call()(but prefer keyword arguments!) - on_exception:
If
on_exceptionisFalse, the default, exceptions fromsubprocess.call()are raised as usual.If
on_exceptionis True, they are ignored.If
on_exceptionis a callable, the line that caused the exception is passed to it.If
on_exceptionis a string, the line causing the exception is printed, prefixed with that string.- echo:
- If
echoisFalse, the default, then commands are silently executed. IfechoisTrue, commands are printed prefixed with$Ifechois a string, commands are printed prefixed with that string Ifechois callable, then each command is passed to it. - iterate:
If
iterateisFalse, the default, then a list of results is returned.Otherwise an iterator of results which is returned, allowing for lazy evaluation.
- encoding:
- Like the argument to
subprocess.call(), except the default is'utf8' - kwargs:
- Named arguments passed on to
subprocess.call()
runs.check_call( commands, *args, iterate=False, encoding='utf8', on_exception=None, echo=False, **kwargs, )Call subprocess.check_call() on each command. If any command has a non-zero returncode, raise subprocess.CallProcessError.
See the help for subprocess.check_call() for more information.
- Arguments:
- commands:
- A string, which gets split into lines on line endings, or a list of strings.
- args:
- Positional arguments to
subprocess.check_call()(but prefer keyword arguments!) - on_exception:
If
on_exceptionisFalse, the default, exceptions fromsubprocess.check_call()are raised as usual.If
on_exceptionis True, they are ignored.If
on_exceptionis a callable, the line that caused the exception is passed to it.If
on_exceptionis a string, the line causing the exception is printed, prefixed with that string.- echo:
- If
echoisFalse, the default, then commands are silently executed. IfechoisTrue, commands are printed prefixed with$Ifechois a string, commands are printed prefixed with that string Ifechois callable, then each command is passed to it. - iterate:
If
iterateisFalse, the default, then a list of results is returned.Otherwise an iterator of results which is returned, allowing for lazy evaluation.
- encoding:
- Like the argument to
subprocess.check_call(), except the default is'utf8' - kwargs:
- Named arguments passed on to
subprocess.check_call()
runs.check_output( commands, *args, iterate=False, encoding='utf8', on_exception=None, echo=False, **kwargs, )Call subprocess.check_output() on each command. If a command has a non-zero exit code, raise a subprocess.CallProcessError. Otherwise, return the results as a list of strings, one for each command. See the help for subprocess.check_output() for more information.
- Arguments:
- commands:
- A string, which gets split into lines on line endings, or a list of strings.
- args:
- Positional arguments to
subprocess.check_output()(but prefer keyword arguments!) - on_exception:
If
on_exceptionisFalse, the default, exceptions fromsubprocess.check_output()are raised as usual.If
on_exceptionis True, they are ignored.If
on_exceptionis a callable, the line that caused the exception is passed to it.If
on_exceptionis a string, the line causing the exception is printed, prefixed with that string.- echo:
- If
echoisFalse, the default, then commands are silently executed. IfechoisTrue, commands are printed prefixed with$Ifechois a string, commands are printed prefixed with that string Ifechois callable, then each command is passed to it. - iterate:
If
iterateisFalse, the default, then a list of results is returned.Otherwise an iterator of results which is returned, allowing for lazy evaluation.
- encoding:
- Like the argument to
subprocess.check_output(), except the default is'utf8' - kwargs:
- Named arguments passed on to
subprocess.check_output()
(automatically generated by doks on 2020-12-16T13:48:26.579866)