runs


Nameruns JSON
Version 1.2.1 PyPI version JSON
download
home_page
Summary🏃 Run a block of text as a subprocess 🏃
upload_time2024-01-25 10:43:25
maintainer
docs_urlNone
authorTom Ritchford
requires_python>=3.8
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            🏃 runs: a better subprocess 🏃
---------------------------------------------------------------------

``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.

.. code-block:: python

    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:

.. code-block:: python

    # ``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.

.. code-block:: python

    result = runs.check_output('echo foo > bar.txt')
    assert result == ['foo > bar.txt\n']

* Pipes don't work.

.. code-block:: python

    result = runs.check_output('echo foo | wc')
    assert result == ['foo | wc \n']

*  Environment variables are not expanded in command lines

.. code-block:: python

    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()``
~~~~~~~~~~

.. code-block:: python

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

(`runs.py, 186-200 <https://github.com/rec/runs/blob/master/runs.py#L186-L200>`_)

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()``
~~~~~~~~~~~~~~~

.. code-block:: python

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

(`runs.py, 186-200 <https://github.com/rec/runs/blob/master/runs.py#L186-L200>`_)

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()``
~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

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

(`runs.py, 186-200 <https://github.com/rec/runs/blob/master/runs.py#L186-L200>`_)

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()``
~~~~~~~~~~~~~~~~~~~~~~~

.. code-block:: python

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

(`runs.py, 186-200 <https://github.com/rec/runs/blob/master/runs.py#L186-L200>`_)

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 <https://github.com/rec/doks/>`_ on 2020-12-16T13:48:26.579866)

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "runs",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "",
    "keywords": "",
    "author": "Tom Ritchford",
    "author_email": "tom@swirly.com",
    "download_url": "https://files.pythonhosted.org/packages/30/2d/82125b2b78d80e26bc0c24cc8d616573d4acd25d12813e277b0d7a6392a5/runs-1.2.1.tar.gz",
    "platform": null,
    "description": "\ud83c\udfc3 runs: a better subprocess \ud83c\udfc3\n---------------------------------------------------------------------\n\n``runs`` has improved versions of ``call()``, ``check_call()``, ``check_output()``,\nand ``run()`` from Python's ``subprocess`` module that handle multiple commands and\nblocks of text, fix some defects, and add some features.\n\n.. code-block:: python\n\n    import runs\n\n    runs('''\n        ls\n        df -k  # or perhaps -h?\n        echo 'Done and done'\n    ''')\n\n---\n\n``subprocess`` is essential but:\n\n* You can only run one command at a time\n\n* Commands to subprocess must be either a sequence of strings or a string,\n  depending on whether ``shell=True`` or not\n\n* Results are returned by default as bytes and not strings\n\n---\n\nThe ``runs`` functions let you run a block of text as a sequence of subprocess\ncalls.\n\n``runs`` provides call-compatible replacements for the functions\n``subprocess.call()``, ``subprocess.check_call()``, ``subprocess.check_output()``,\nand ``subprocess.run()``\n\nEach replacement function takes a block of text, which is split into individual\ncommand lines, or a list of commands, and returns a list of values, one for\neach command.  A block of text can contain line continuations, and comments,\nwhich are ignored.\n\nThe replacement functions also add optional logging, error handling,\nand lazy evaluation, and use UTF-8 encoding by default.\n\nThe module ``runs`` is callable - ``runs()`` is a synonym for ``runs.run()``.\n\nEXAMPLES:\n\n.. code-block:: python\n\n    # ``runs()`` or ``runs.run()`` writes to stdout and stderr just as if you'd run\n    # the commands from the terminal\n\n    import runs\n\n    runs('echo \"hello, world!\"')  # prints hello, world!\n\n    # runs.check_output() returns a list, one string result for each command\n\n    results = check_output('''\n        echo  line   one  # Here's line one.\n        echo   'line \"  two  \"'  # and two!\n    ''')\n    assert results == ['line one', 'line \"  two  \"']\n\n    # Line continuations work too, either single or double\n    runs('''\n        ls -cail\n\n        # One command that takes many lines.\n        g++ -DDEBUG  -O0 -g -std=c++17 -pthread -I ./include -lm -lstdc++ \\\n          -Wall -Wextra -Wno-strict-aliasing -Wpedantic \\\\\n          -MMD -MP -MF -c src/tests.cpp -o build/./src/tests.cpp.o\n\n        echo DONE\n     ''')\n\nNOTES:\n\nExactly like ``subprocess``, ``runs`` differs from the shell in a few ways, so\nyou can't just paste your shell scripts in:\n\n* Redirection doesn't work.\n\n.. code-block:: python\n\n    result = runs.check_output('echo foo > bar.txt')\n    assert result == ['foo > bar.txt\\n']\n\n* Pipes don't work.\n\n.. code-block:: python\n\n    result = runs.check_output('echo foo | wc')\n    assert result == ['foo | wc \\n']\n\n*  Environment variables are not expanded in command lines\n\n.. code-block:: python\n\n    result = runs.check_output('echo $FOO', env={'FOO': 'bah!'})\n    assert result == ['$FOO\\n']\n\nEnvironment variables are exported to the subprocess, absolutely,\nbut no environment variable expension happens on command lines.\n\nAPI\n===\n\n``runs()``\n~~~~~~~~~~\n\n.. code-block:: python\n\n  runs(\n       commands,\n       *args,\n       iterate=False,\n       encoding='utf8',\n       on_exception=None,\n       echo=False,\n       **kwargs,\n  )\n\n(`runs.py, 186-200 <https://github.com/rec/runs/blob/master/runs.py#L186-L200>`_)\n\nCall ``subprocess.run()`` on each command.\nReturn a list of ``subprocess.CompletedProcess`` instances.\nSee the help for ``subprocess.run()`` for more information.\n\nArguments:\n  commands:\n    A string, which gets split into lines on line endings, or a list of\n    strings.\n\n  args:\n    Positional arguments to ``subprocess.run()`` (but prefer keyword\n    arguments!)\n\n  on_exception:\n    If ``on_exception`` is ``False``, the default, exceptions from\n    ``subprocess.run()`` are raised as usual.\n\n    If ``on_exception`` is True, they are ignored.\n\n    If ``on_exception`` is a callable, the line that caused the exception is\n    passed to it.\n\n    If ``on_exception`` is a string, the line causing the exception\n    is printed, prefixed with that string.\n\n  echo:\n    If ``echo`` is ``False``, the default, then commands are silently executed.\n    If ``echo`` is ``True``, commands are printed prefixed with ``$``\n    If ``echo`` is a string, commands are printed prefixed with that string\n    If ``echo`` is callable, then each command is passed to it.\n\n  iterate:\n    If ``iterate`` is ``False``, the default, then a list of results is\n    returned.\n\n    Otherwise an iterator of results which is returned, allowing for lazy\n    evaluation.\n\n  encoding:\n    Like the argument to ``subprocess.run()``, except the default  is\n    ``'utf8'``\n\n  kwargs:\n    Named arguments passed on to ``subprocess.run()``\n\n``runs.call()``\n~~~~~~~~~~~~~~~\n\n.. code-block:: python\n\n  runs.call(\n       commands,\n       *args,\n       iterate=False,\n       encoding='utf8',\n       on_exception=None,\n       echo=False,\n       **kwargs,\n  )\n\n(`runs.py, 186-200 <https://github.com/rec/runs/blob/master/runs.py#L186-L200>`_)\n\nCall ``subprocess.call()`` on each command.\nReturn a list of integer returncodes, one for each command executed.\nSee the help for ``subprocess.call()`` for more information.\n\nArguments:\n  commands:\n    A string, which gets split into lines on line endings, or a list of\n    strings.\n\n  args:\n    Positional arguments to ``subprocess.call()`` (but prefer keyword\n    arguments!)\n\n  on_exception:\n    If ``on_exception`` is ``False``, the default, exceptions from\n    ``subprocess.call()`` are raised as usual.\n\n    If ``on_exception`` is True, they are ignored.\n\n    If ``on_exception`` is a callable, the line that caused the exception is\n    passed to it.\n\n    If ``on_exception`` is a string, the line causing the exception\n    is printed, prefixed with that string.\n\n  echo:\n    If ``echo`` is ``False``, the default, then commands are silently executed.\n    If ``echo`` is ``True``, commands are printed prefixed with ``$``\n    If ``echo`` is a string, commands are printed prefixed with that string\n    If ``echo`` is callable, then each command is passed to it.\n\n  iterate:\n    If ``iterate`` is ``False``, the default, then a list of results is\n    returned.\n\n    Otherwise an iterator of results which is returned, allowing for lazy\n    evaluation.\n\n  encoding:\n    Like the argument to ``subprocess.call()``, except the default  is\n    ``'utf8'``\n\n  kwargs:\n    Named arguments passed on to ``subprocess.call()``\n\n``runs.check_call()``\n~~~~~~~~~~~~~~~~~~~~~\n\n.. code-block:: python\n\n  runs.check_call(\n       commands,\n       *args,\n       iterate=False,\n       encoding='utf8',\n       on_exception=None,\n       echo=False,\n       **kwargs,\n  )\n\n(`runs.py, 186-200 <https://github.com/rec/runs/blob/master/runs.py#L186-L200>`_)\n\nCall ``subprocess.check_call()`` on each command.\nIf any command has a non-zero returncode, raise ``subprocess.CallProcessError``.\n\nSee the help for ``subprocess.check_call()`` for more information.\n\nArguments:\n  commands:\n    A string, which gets split into lines on line endings, or a list of\n    strings.\n\n  args:\n    Positional arguments to ``subprocess.check_call()`` (but prefer keyword\n    arguments!)\n\n  on_exception:\n    If ``on_exception`` is ``False``, the default, exceptions from\n    ``subprocess.check_call()`` are raised as usual.\n\n    If ``on_exception`` is True, they are ignored.\n\n    If ``on_exception`` is a callable, the line that caused the exception is\n    passed to it.\n\n    If ``on_exception`` is a string, the line causing the exception\n    is printed, prefixed with that string.\n\n  echo:\n    If ``echo`` is ``False``, the default, then commands are silently executed.\n    If ``echo`` is ``True``, commands are printed prefixed with ``$``\n    If ``echo`` is a string, commands are printed prefixed with that string\n    If ``echo`` is callable, then each command is passed to it.\n\n  iterate:\n    If ``iterate`` is ``False``, the default, then a list of results is\n    returned.\n\n    Otherwise an iterator of results which is returned, allowing for lazy\n    evaluation.\n\n  encoding:\n    Like the argument to ``subprocess.check_call()``, except the default  is\n    ``'utf8'``\n\n  kwargs:\n    Named arguments passed on to ``subprocess.check_call()``\n\n``runs.check_output()``\n~~~~~~~~~~~~~~~~~~~~~~~\n\n.. code-block:: python\n\n  runs.check_output(\n       commands,\n       *args,\n       iterate=False,\n       encoding='utf8',\n       on_exception=None,\n       echo=False,\n       **kwargs,\n  )\n\n(`runs.py, 186-200 <https://github.com/rec/runs/blob/master/runs.py#L186-L200>`_)\n\nCall ``subprocess.check_output()`` on each command.\nIf a command has a non-zero exit code, raise a ``subprocess.CallProcessError``.\nOtherwise, return the results as a list of strings, one for each command.\nSee the help for ``subprocess.check_output()`` for more information.\n\nArguments:\n  commands:\n    A string, which gets split into lines on line endings, or a list of\n    strings.\n\n  args:\n    Positional arguments to ``subprocess.check_output()`` (but prefer keyword\n    arguments!)\n\n  on_exception:\n    If ``on_exception`` is ``False``, the default, exceptions from\n    ``subprocess.check_output()`` are raised as usual.\n\n    If ``on_exception`` is True, they are ignored.\n\n    If ``on_exception`` is a callable, the line that caused the exception is\n    passed to it.\n\n    If ``on_exception`` is a string, the line causing the exception\n    is printed, prefixed with that string.\n\n  echo:\n    If ``echo`` is ``False``, the default, then commands are silently executed.\n    If ``echo`` is ``True``, commands are printed prefixed with ``$``\n    If ``echo`` is a string, commands are printed prefixed with that string\n    If ``echo`` is callable, then each command is passed to it.\n\n  iterate:\n    If ``iterate`` is ``False``, the default, then a list of results is\n    returned.\n\n    Otherwise an iterator of results which is returned, allowing for lazy\n    evaluation.\n\n  encoding:\n    Like the argument to ``subprocess.check_output()``, except the default  is\n    ``'utf8'``\n\n  kwargs:\n    Named arguments passed on to ``subprocess.check_output()``\n\n(automatically generated by `doks <https://github.com/rec/doks/>`_ on 2020-12-16T13:48:26.579866)\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "\ud83c\udfc3 Run a block of text as a subprocess \ud83c\udfc3",
    "version": "1.2.1",
    "project_urls": null,
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d774cb1ca09152bcca9ebed1a9a3cd8c66639d68bee528233e84c7db1c94c99d",
                "md5": "78731b16cc323271dfa8a95f5a4780fb",
                "sha256": "f103386deb84983d445e61b56de48a006691289a17f80214fe593e858d193a12"
            },
            "downloads": -1,
            "filename": "runs-1.2.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "78731b16cc323271dfa8a95f5a4780fb",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 6892,
            "upload_time": "2024-01-25T10:43:23",
            "upload_time_iso_8601": "2024-01-25T10:43:23.236361Z",
            "url": "https://files.pythonhosted.org/packages/d7/74/cb1ca09152bcca9ebed1a9a3cd8c66639d68bee528233e84c7db1c94c99d/runs-1.2.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "302d82125b2b78d80e26bc0c24cc8d616573d4acd25d12813e277b0d7a6392a5",
                "md5": "ca6c7d615e0d01cfe1173c9e2fd88e01",
                "sha256": "4da28358b53d92a7b49cce744387de0bcb623edbb48941a58cd40291ef4c2301"
            },
            "downloads": -1,
            "filename": "runs-1.2.1.tar.gz",
            "has_sig": false,
            "md5_digest": "ca6c7d615e0d01cfe1173c9e2fd88e01",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 5264,
            "upload_time": "2024-01-25T10:43:25",
            "upload_time_iso_8601": "2024-01-25T10:43:25.026414Z",
            "url": "https://files.pythonhosted.org/packages/30/2d/82125b2b78d80e26bc0c24cc8d616573d4acd25d12813e277b0d7a6392a5/runs-1.2.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-01-25 10:43:25",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "runs"
}
        
Elapsed time: 0.17055s