Skip to main content

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=True or 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.

API

runs()

runs(
     commands,
     *args,
     iterate=False,
     encoding='utf8',
     on_exception=None,
     echo=False,
     **kwargs,
)

(runs.py, 186-200)

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_exception is False, the default, exceptions from subprocess.run() are raised as usual.

If on_exception is True, they are ignored.

If on_exception is a callable, the line that caused the exception is passed to it.

If on_exception is a string, the line causing the exception is printed, prefixed with that string.

echo:

If echo is False, the default, then commands are silently executed. If echo is True, commands are printed prefixed with $ If echo is a string, commands are printed prefixed with that string If echo is callable, then each command is passed to it.

iterate:

If iterate is False, 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()

runs.call(
     commands,
     *args,
     iterate=False,
     encoding='utf8',
     on_exception=None,
     echo=False,
     **kwargs,
)

(runs.py, 186-200)

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_exception is False, the default, exceptions from subprocess.call() are raised as usual.

If on_exception is True, they are ignored.

If on_exception is a callable, the line that caused the exception is passed to it.

If on_exception is a string, the line causing the exception is printed, prefixed with that string.

echo:

If echo is False, the default, then commands are silently executed. If echo is True, commands are printed prefixed with $ If echo is a string, commands are printed prefixed with that string If echo is callable, then each command is passed to it.

iterate:

If iterate is False, 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()

runs.check_call(
     commands,
     *args,
     iterate=False,
     encoding='utf8',
     on_exception=None,
     echo=False,
     **kwargs,
)

(runs.py, 186-200)

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_exception is False, the default, exceptions from subprocess.check_call() are raised as usual.

If on_exception is True, they are ignored.

If on_exception is a callable, the line that caused the exception is passed to it.

If on_exception is a string, the line causing the exception is printed, prefixed with that string.

echo:

If echo is False, the default, then commands are silently executed. If echo is True, commands are printed prefixed with $ If echo is a string, commands are printed prefixed with that string If echo is callable, then each command is passed to it.

iterate:

If iterate is False, 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()

runs.check_output(
     commands,
     *args,
     iterate=False,
     encoding='utf8',
     on_exception=None,
     echo=False,
     **kwargs,
)

(runs.py, 186-200)

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_exception is False, the default, exceptions from subprocess.check_output() are raised as usual.

If on_exception is True, they are ignored.

If on_exception is a callable, the line that caused the exception is passed to it.

If on_exception is a string, the line causing the exception is printed, prefixed with that string.

echo:

If echo is False, the default, then commands are silently executed. If echo is True, commands are printed prefixed with $ If echo is a string, commands are printed prefixed with that string If echo is callable, then each command is passed to it.

iterate:

If iterate is False, 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)

Metadata

Release files for runs 1.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for runs 1.3.0
File Size Uploaded
runs-1.3.0.tar.gz 4.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for runs 1.3.0
File Interpreter ABI Platform
runs-1.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 11.0 kB

Release files / runs-1.3.0.tar.gz

Download URL runs-1.3.0.tar.gz
Size 4.6 kB
Tags Source
SHA-256 checksum
How to use checksums
cca304b631dbefec598c7bfbcfb50d6feace6d3a968734b67fd42d3c728f5a05
BLAKE2b-256 checksum
How to use checksums
f2ae095cb626504733e288a81f871f86b10530b787d77c50193c170daaca0df1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / runs-1.3.0-py3-none-any.whl

Download URL runs-1.3.0-py3-none-any.whl
Size 6.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e71a551cfa8da9ef882cac1d5a108bda78c9edee5b8d87e37c1003da5b6a7bed
BLAKE2b-256 checksum
How to use checksums
4fb6049c75d399ccf6e25abea0652b85bf7e7e101e0300aa9c1d284ad7061c0b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

1.3.0 This release

2 release files

1.2.2

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.3.2

2 release files

0.3.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page