{ "info": { "author": "John Didion", "author_email": "github@didion.net", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7" ], "description": "[![Travis CI](https://travis-ci.org/jdidion/subby.svg?branch=master)](https://travis-ci.org/jdidion/subby)\n[![Code Coverage](https://codecov.io/gh/jdidion/subby/branch/master/graph/badge.svg)](https://codecov.io/gh/jdidion/subby)\n\nSubby is a small Python library with the goal of simplifying the use of subprocesses. Subby is similar to [delegator.py](https://github.com/amitt001/delegator.py), but it adds a few additional features and excludes others (e.g. no `pexpect` support).\n\n## Requirements\n\nThe only requirement is python 3.6+. There are no other 3rd-party runtime dependencies. The `pytest` and `coverage` packages are required for testing.\n\n## Installation\n\n`pip install subby`\n\n## Usage\n\nSubby's primary interface is the `run` function. It takes a list of commands and executes them. If there is are multiple commands, they are chained (i.e. piped) together.\n\n```python\nimport subby\n\n# We can pass input to the stdin of the command as bytes\ninput_str = \"foo\\nbar\"\n\n# The following three commands are equivalent; each returns a\n# `Processes` object that can be used to inspect and control\n# the process(es).\np1 = subby.run([[\"grep foo\", \"wc -l\"]], stdin=input_str)\np2 = subby.run((\"grep foo\", \"wc -l\"), stdin=input_str)\np3 = subby.run(\"grep foo | wc -l\", stdin=input_str)\n\n# The `done` property tells us whether the processes have finished\nassert p1.done and p2.done and p3.done\n\n# The `output` property provides the output of the command\nassert p1.output == p2.output == p3.output == \"1\"\n```\n\n### Raw mode\n\nBy default, text I/O is used for stdin/stdout/stderr. You can instead use raw I/O (bytes) by passing `mode=bytes`.\n\n```\nimport subby\n\nassert b\"1\" == subby.run(\n \"grep foo | wc -l\", stdin=\"foo\\nbar\", mode=bytes\n).output\n```\n\n### Non-blocking processes\n\nBy default, the `run` function blocks until the processes are finshed running. This behavior can be changed by passing `block=False`, in which case, the caller is responsible for checking the status and/or calling the `Processes.block()` method manually.\n\n```python\nimport subby\nimport time\n\np = subby.run(\"sleep 10\", block=False)\nfor i in range(5):\n if p.done:\n break\n else:\n time.sleep(1)\nelse:\n # A timeout can be used to kill the process if it doesn't\n # complete in a certain amount of time. By default, block()\n # raises an error if the return code is non-zero.\n p.block(timeout=10, raise_on_error=False)\n \n # The process can also be killed manually.\n p.kill()\n\n# The `Processes.ok` property is True if the processes have\n# finished and the return code is 0.\nif not p.ok:\n # The `Processes.output` and `Processes.error` properties\n # provide access to the process stdout and stderr.\n print(f\"The command failed: stderr={p.error}\")\n```\n\n### Convenience method\n\nThere is also a convenience method, `sub`, equivalent to calling `run` with `mode=str` and `block=True` and returning the `output` attribute (stdout) of the resulting `Processes` object.\n\n```python\nimport subby\n\nassert subby.sub(\"grep foo | wc -l\", stdin=\"foo\\nbar\") == \"1\"\n```\n\n### stdin/stdout/stderr\n\nSubby supports several different types of arguments for stdin, stdout, and stderr:\n\n* A file: specified as a `pathlib.Path`; for stdin, the content is read from the file, whereas for stdout/stderr the content is written to the file (and is thus not available via the `output`/`error` properties).\n* A bytes string: for stdin, the bytes are written to a temporary file, which is passed to the process stdin.\n* One of the values provided by the `StdType` enumeration:\n * PIPE: for stdout/stderr, `subprocess.PIPE` is used, giving the caller direct access to the process stdout/stderr streams.\n * BUFFER: for stdout/stderr, a temporary file is used, and the contents are made available via the `output`/`error` properties after the process completes.\n * SYS: stdin/stdout/stderr is passed through from the main process (i.e. the `sys.stdin/sys.stdout/sys.stderr` streams).\n\nBy default, the stderr streams of all processes in a chain are captured (you can disable this by passing `capture_stderr=False` to `run()`).\n\n```python\nimport subby\np = subby.run(\"echo -n hi | tee /dev/stderr | tee /dev/stderr\")\nassert p.output == b\"hi\"\nassert p.get_all_stderr() == [b\"\", b\"hi\", b\"hi\"]\n```\n\n### Logging\n\nBy default, all executed commands are logged (with loglevel INFO). You can disable this behavior by passing `echo=False` to `run()`.\n\n```python\nimport subby\nsubby.run(\"touch foo\") # Echoes \"touch foo\" to the log with level INFO\nsubby.run(\"login -p mypassword\", echo=False) # Does not echo mypassword\n```\n\n### Return codes\n\nBy default, Subby treats a return code of `0` as success and all other return codes as failure. In some cases, this is not the desired behavior. A well-known example is `grep`, which has a returncode of `1` when no lines are matched. To ignore additional return codes, set the `allowed_return_codes` keyword argument to `run()`.\n\n```python\nimport subby\nsubby.run(\"echo foo | grep bar\") # Raises CalledProcessError\nsubby.run(\"echo foo | grep bar\", allowed_return_codes=(0, 1))\n```\n## Contributing\n\nSubby is considered to be largely feature-complete, but if you find a bug or have a suggestion for improvement, please submit an issue (or even better, a pull request).\n\n## Acknowledgements\n\nSubby was inspired by [delegator.py](https://github.com/amitt001/delegator.py).\n\nSubby was originally written as part of the [dxpy.sugar](https://github.com/dnanexus/dx-toolkit/tree/SCI-1321_dx_sugar/src/python/dxpy/sugar) package, but because it is (hopefully) useful more generally, it is being made available as a separate package. [@Damien-Black](https://github.com/@Damien-Black) and [@msimbirsky](https://github.com/msimbirsky) contributed code and reviews.\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/jdidion/subby", "keywords": "", "license": "Apache-2.0", "maintainer": "John Didion", "maintainer_email": "github@didion.net", "name": "subby", "package_url": "https://pypi.org/project/subby/", "platform": "", "project_url": "https://pypi.org/project/subby/", "project_urls": { "Homepage": "https://github.com/jdidion/subby", "Repository": "https://github.com/jdidion/subby.git" }, "release_url": "https://pypi.org/project/subby/0.1.6/", "requires_dist": null, "requires_python": ">=3.6,<4.0", "summary": "Subprocesses simplified", "version": "0.1.6" }, "last_serial": 5882715, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "f39081b2cccf2c0322ec69a22ebb6530", "sha256": "cc273ed32d82c3c9037876eae4a67542ef0a84aab9af583d890aa448761304ea" }, "downloads": -1, "filename": "subby-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "f39081b2cccf2c0322ec69a22ebb6530", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<4.0", "size": 11426, "upload_time": "2019-09-09T20:40:26", "url": "https://files.pythonhosted.org/packages/a2/7c/8d0c758d65bde7588205fa2d7d533bf756b1b31afae4943d28bb87712660/subby-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b07a3e006f0849c238b48bc32eb490bd", "sha256": "56dc055b7166ddf5e43f12d62d08958d34710bd183e9b177e2f792636d9ef093" }, "downloads": -1, "filename": "subby-0.1.0.tar.gz", "has_sig": false, "md5_digest": "b07a3e006f0849c238b48bc32eb490bd", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<4.0", "size": 10417, "upload_time": "2019-09-09T20:40:28", "url": "https://files.pythonhosted.org/packages/2f/ed/aace66c67168ba12d37324485ac88a8a59e0801f8d1fd9cc5b78b490e054/subby-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "4b2fb3183bee9315f884f900bcd04634", "sha256": "22e615c8b9c3f0db94227064063cf7ab05e6c97f5d1372da27274e5dc8fa317d" }, "downloads": -1, "filename": "subby-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "4b2fb3183bee9315f884f900bcd04634", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<4.0", "size": 13277, "upload_time": "2019-09-09T20:49:57", "url": "https://files.pythonhosted.org/packages/44/09/0d456803218c221de8e0db84d7f6ac5e66868898c5cee9d6f7dd4f16de89/subby-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6d94cca6f39f0f00256ba9c9683b5641", "sha256": "d7021350aa664af9f275e0b942a06155c6f97c5940d9b6d436e812f87f877d4d" }, "downloads": -1, "filename": "subby-0.1.1.tar.gz", "has_sig": false, "md5_digest": "6d94cca6f39f0f00256ba9c9683b5641", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<4.0", "size": 13764, "upload_time": "2019-09-09T20:49:58", "url": "https://files.pythonhosted.org/packages/10/b2/8b32367441600ae1eaedc53a7de38084d3f74a7ad30eef05c984f8afe7e1/subby-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "9ad8b01983118d6f1b8a85775f73eabc", "sha256": "ef273122c784c0b353ddb7a46cf30e0031a47891508834d64f041b5b63ad9d74" }, "downloads": -1, "filename": "subby-0.1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "9ad8b01983118d6f1b8a85775f73eabc", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<4.0", "size": 13399, "upload_time": "2019-09-09T23:52:49", "url": "https://files.pythonhosted.org/packages/b1/a6/1ed890c27c13c6bb118a52276e06c79f2dc44928035545449de6917620c7/subby-0.1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "15aff86631b1a99dbe3720a8abb9959e", "sha256": "90b91a42de461d90a40d146ead3cf7bdf61bc7197d23a79e278034406397ae45" }, "downloads": -1, "filename": "subby-0.1.2.tar.gz", "has_sig": false, "md5_digest": "15aff86631b1a99dbe3720a8abb9959e", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<4.0", "size": 13876, "upload_time": "2019-09-09T23:52:50", "url": "https://files.pythonhosted.org/packages/72/db/1bf60ca772bb7a8317038ce166bbc9b6a5dda640ccb08f9606aaf7e315d5/subby-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "0596bf293a5548a58f9e72fd65f41c6b", "sha256": "ce86bf9cd4b1cd411e0cabfd12ebe16a699da7c24fab115ba0d4eb51c417684e" }, "downloads": -1, "filename": "subby-0.1.3-py3-none-any.whl", "has_sig": false, "md5_digest": "0596bf293a5548a58f9e72fd65f41c6b", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<4.0", "size": 14649, "upload_time": "2019-09-15T20:21:13", "url": "https://files.pythonhosted.org/packages/de/af/9bc233e3992e8f50e96e58f94020c2412c856ebbc6fefbb59f762f4bfcba/subby-0.1.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a07d483d49babb975417a9f4a22c54fc", "sha256": "f4d60a6a196c8293c0d6fab0aa732ae7d33121ea03e4a3ec2e986ebc5c9964bc" }, "downloads": -1, "filename": "subby-0.1.3.tar.gz", "has_sig": false, "md5_digest": "a07d483d49babb975417a9f4a22c54fc", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<4.0", "size": 15788, "upload_time": "2019-09-15T20:21:14", "url": "https://files.pythonhosted.org/packages/77/91/1d1c7144b4bd675025c02d40ffd969cccbcec1fde5356dbf01a9f2e2c753/subby-0.1.3.tar.gz" } ], "0.1.4": [ { "comment_text": "", "digests": { "md5": "52147e5a7bfdcca988d651bc6241acdb", "sha256": "414a365f36819307e3657748c0bbc00326e974e1995e93d884a3169767d801ce" }, "downloads": -1, "filename": "subby-0.1.4-py3-none-any.whl", "has_sig": false, "md5_digest": "52147e5a7bfdcca988d651bc6241acdb", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<4.0", "size": 14719, "upload_time": "2019-09-15T20:28:55", "url": "https://files.pythonhosted.org/packages/d0/b4/6721795815dc48403e752a0aacc65a8ec42ac82fc6def2d43de81fbd6b34/subby-0.1.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d88fcecb6f92680bb54a3cad6786d0ef", "sha256": "89bd17d08cffef2f4835a25e96a7bb1f300991e703e439c7ac2db942a53b1239" }, "downloads": -1, "filename": "subby-0.1.4.tar.gz", "has_sig": false, "md5_digest": "d88fcecb6f92680bb54a3cad6786d0ef", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<4.0", "size": 15856, "upload_time": "2019-09-15T20:28:56", "url": "https://files.pythonhosted.org/packages/6b/34/dbea247d00c87e5f2aaeccd69b9fa6633cd8af78b37c7a9f4186020ef473/subby-0.1.4.tar.gz" } ], "0.1.5": [ { "comment_text": "", "digests": { "md5": "54a87b4d18c14e25cc55fc6c75736695", "sha256": "60fc0c57086c84e0aa3217b02fbca021240c363ec678566409c7581efebfa658" }, "downloads": -1, "filename": "subby-0.1.5-py3-none-any.whl", "has_sig": false, "md5_digest": "54a87b4d18c14e25cc55fc6c75736695", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<4.0", "size": 14835, "upload_time": "2019-09-15T21:07:29", "url": "https://files.pythonhosted.org/packages/e7/21/298e1c8c3250fac08daa9f9dc7149681cbd8a9955813a00229739904707b/subby-0.1.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "43587468b0fd1deaca8a53b6578a7b78", "sha256": "e24ac27c745e110601be9c0fa4c8835b3491547b5053b165d3126a4167e63d1a" }, "downloads": -1, "filename": "subby-0.1.5.tar.gz", "has_sig": false, "md5_digest": "43587468b0fd1deaca8a53b6578a7b78", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<4.0", "size": 15937, "upload_time": "2019-09-15T21:07:31", "url": "https://files.pythonhosted.org/packages/f1/ba/115947c5b76ad68165df2f160f1ea7d77a3afa186675468f8fc627e8f6e3/subby-0.1.5.tar.gz" } ], "0.1.6": [ { "comment_text": "", "digests": { "md5": "77218d4f630850269ed0d88b32a68755", "sha256": "595db9e5001394cf796c7872ee0b7b3dc336d8071096afff1e1f2e7495a0c7bb" }, "downloads": -1, "filename": "subby-0.1.6-py3-none-any.whl", "has_sig": false, "md5_digest": "77218d4f630850269ed0d88b32a68755", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<4.0", "size": 15189, "upload_time": "2019-09-25T02:09:01", "url": "https://files.pythonhosted.org/packages/2e/08/e5b1338106c9cc805549033d0b61dc087d770eeda3742896791d7ea9ddf3/subby-0.1.6-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d83d51cdcaf5c901d0d9c2a08a8b5587", "sha256": "458981e5db3886766410a72fe19c9c81d1aa881856d2ec57f9149cd06e7b13d8" }, "downloads": -1, "filename": "subby-0.1.6.tar.gz", "has_sig": false, "md5_digest": "d83d51cdcaf5c901d0d9c2a08a8b5587", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<4.0", "size": 16395, "upload_time": "2019-09-25T02:09:03", "url": "https://files.pythonhosted.org/packages/2a/ef/26298598930d3f2ce683fe4967ed5432ac2525ff6f697f70d68f49820597/subby-0.1.6.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "77218d4f630850269ed0d88b32a68755", "sha256": "595db9e5001394cf796c7872ee0b7b3dc336d8071096afff1e1f2e7495a0c7bb" }, "downloads": -1, "filename": "subby-0.1.6-py3-none-any.whl", "has_sig": false, "md5_digest": "77218d4f630850269ed0d88b32a68755", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6,<4.0", "size": 15189, "upload_time": "2019-09-25T02:09:01", "url": "https://files.pythonhosted.org/packages/2e/08/e5b1338106c9cc805549033d0b61dc087d770eeda3742896791d7ea9ddf3/subby-0.1.6-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d83d51cdcaf5c901d0d9c2a08a8b5587", "sha256": "458981e5db3886766410a72fe19c9c81d1aa881856d2ec57f9149cd06e7b13d8" }, "downloads": -1, "filename": "subby-0.1.6.tar.gz", "has_sig": false, "md5_digest": "d83d51cdcaf5c901d0d9c2a08a8b5587", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6,<4.0", "size": 16395, "upload_time": "2019-09-25T02:09:03", "url": "https://files.pythonhosted.org/packages/2a/ef/26298598930d3f2ce683fe4967ed5432ac2525ff6f697f70d68f49820597/subby-0.1.6.tar.gz" } ] }