{ "info": { "author": "Peter Odding", "author_email": "peter@peterodding.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: POSIX", "Operating System :: Unix", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Topic :: Communications", "Topic :: Scientific/Engineering :: Human Machine Interfaces", "Topic :: Software Development", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: User Interfaces", "Topic :: System :: Shells", "Topic :: System :: Systems Administration", "Topic :: System :: System Shells", "Topic :: Terminals", "Topic :: Text Processing :: General" ], "description": "capturer: Easily capture stdout/stderr of the current process and subprocesses\n==============================================================================\n\n.. image:: https://travis-ci.org/xolox/python-capturer.svg?branch=master\n :target: https://travis-ci.org/xolox/python-capturer\n\n.. image:: https://coveralls.io/repos/xolox/python-capturer/badge.svg?branch=master\n :target: https://coveralls.io/r/xolox/python-capturer?branch=master\n\nThe `capturer` package makes it easy to capture the stdout_ and stderr_ streams\nof the current process *and subprocesses*. Output can be relayed to the\nterminal in real time but is also available to the Python program for\nadditional processing. It's currently tested on cPython 2.6, 2.7, 3.4, 3.5, 3.6\nand PyPy (2.7). It's tested on Linux and Mac OS X and may work on other unixes\nbut definitely won't work on Windows (due to the use of the platform dependent\npty_ module). For usage instructions please refer to the documentation_.\n\n.. contents::\n :local:\n\nStatus\n------\n\nThe `capturer` package was developed as a proof of concept over the course of a\nweekend, because I was curious to see if it could be done (reliably). After a\nweekend of extensive testing it seems to work fairly well so I'm publishing the\ninitial release as version 1.0, however I still consider this a proof of\nconcept because I don't have extensive \"production\" experience using it yet.\nHere's hoping it works as well in practice as it did during my testing :-).\n\nInstallation\n------------\n\nThe `capturer` package is available on PyPI_ which means installation should be\nas simple as:\n\n.. code-block:: sh\n\n $ pip install capturer\n\nThere's actually a multitude of ways to install Python packages (e.g. the `per\nuser site-packages directory`_, `virtual environments`_ or just installing\nsystem wide) and I have no intention of getting into that discussion here, so\nif this intimidates you then read up on your options before returning to these\ninstructions ;-).\n\nGetting started\n---------------\n\nThe easiest way to capture output is to use a context manager:\n\n.. code-block:: python\n\n import subprocess\n from capturer import CaptureOutput\n\n with CaptureOutput() as capturer:\n # Generate some output from Python.\n print \"Output from Python\"\n # Generate output from a subprocess.\n subprocess.call([\"echo\", \"Output from a subprocess\"])\n # Get the output in each of the supported formats.\n assert capturer.get_bytes() == b'Output from Python\\r\\nOutput from a subprocess\\r\\n'\n assert capturer.get_lines() == [u'Output from Python', u'Output from a subprocess']\n assert capturer.get_text() == u'Output from Python\\nOutput from a subprocess'\n\nThe use of a context manager (`the with statement`_) ensures that output\ncapturing is enabled and disabled at the appropriate time, regardless of\nwhether exceptions interrupt the normal flow of processing.\n\nNote that the first call to `get_bytes()`_, `get_lines()`_ or `get_text()`_\nwill stop the capturing of output by default. This is intended as a sane\ndefault to prevent partial reads (which can be confusing as hell when you don't\nhave experience with them). So we could have simply used ``print`` to show\nthe results without causing a recursive \"captured output is printed and then\ncaptured again\" loop. There's an optional ``partial=True`` keyword argument\nthat can be used to disable this behavior (please refer to the documentation_\nfor details).\n\nDesign choices\n--------------\n\nThere are existing solutions out there to capture the stdout_ and stderr_\nstreams of (Python) processes. The `capturer` package was created for a very\nspecific use case that wasn't catered for by existing solutions (that I could\nfind). This section documents the design choices that guided the development of\nthe `capturer` package:\n\n.. contents::\n :local:\n\nIntercepts writes to low level file descriptors\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nLibraries like capture_ and iocapture_ change Python's sys.stdout_ and\nsys.stderr_ file objects to fake file objects (using StringIO_). This enables\ncapturing of (most) output written to the stdout_ and stderr_ streams from the\nsame Python process, however any output from subprocesses is unaffected by the\nredirection and not captured.\n\nThe `capturer` package instead intercepts writes to low level file descriptors\n(similar to and inspired by `how pytest does it`_). This enables capturing of\noutput written to the standard output and error streams from the same Python\nprocess as well as any subprocesses.\n\nUses a pseudo terminal to emulate a real terminal\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe `capturer` package uses a pseudo terminal created using `pty.openpty()`_ to\ncapture output. This means subprocesses will use ANSI escape sequences because\nthey think they're connected to a terminal. In the current implementation you\ncan't opt out of this, but feel free to submit a feature request to change this\n:-). This does have some drawbacks:\n\n- The use of `pty.openpty()`_ means you need to be running in a UNIX like\n environment for `capturer` to work (Windows definitely isn't supported).\n\n- All output captured is relayed on the stderr_ stream by default, so capturing\n changes the semantics of your programs. How much this matters obviously\n depends on your use case. For the use cases that triggered me to create\n `capturer` it doesn't matter, which explains why this is the default mode.\n\n There is experimental support for capturing stdout_ and stderr_ separately\n and relaying captured output to the appropriate original stream. Basically\n you call ``CaptureOutput(merged=False)`` and then you use the ``stdout`` and\n ``stderr`` attributes of the ``CaptureOutput`` object to get at the output\n captured on each stream.\n\n I say experimental because this method of capturing can unintentionally\n change the order in which captured output is emitted, in order to avoid\n interleaving output emitted on the stdout_ and stderr_ streams (which would\n most likely result in incomprehensible output). Basically output is relayed\n on each stream separately after each line break. This means interactive\n prompts that block on reading from standard input without emitting a line\n break won't show up (until it's too late ;-).\n\nRelays output to the terminal in real time\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe main use case of `capturer` is to capture all output of a snippet of Python\ncode (including any output by subprocesses) but also relay the output to the\nterminal in real time. This has a couple of useful properties:\n\n- Long running operations can provide the operator with real time feedback by\n emitting output on the terminal. This sounds obvious (and it is!) but it is\n non-trivial to implement (an understatement :-) when you *also* want to\n capture the output.\n\n- Programs like gpg_ and ssh_ that use interactive password prompts will render\n their password prompt on the terminal in real time. This avoids the awkward\n interaction where a password prompt is silenced but the program still hangs,\n waiting for input on stdin_.\n\nContact\n-------\n\nThe latest version of `capturer` is available on PyPI_ and GitHub_. The\ndocumentation is hosted on `Read the Docs`_. For bug reports please create an\nissue on GitHub_. If you have questions, suggestions, etc. feel free to send me\nan e-mail at `peter@peterodding.com`_.\n\nLicense\n-------\n\nThis software is licensed under the `MIT license`_.\n\n\u00a9 2017 Peter Odding.\n\nA big thanks goes out to the pytest_ developers because pytest's mechanism for\ncapturing the output of subprocesses provided inspiration for the `capturer`\npackage. No code was copied, but both projects are MIT licensed anyway, so it's\nnot like it's very relevant :-).\n\n.. External references:\n.. _capture: https://pypi.python.org/pypi/capture\n.. _documentation: https://capturer.readthedocs.io\n.. _get_bytes(): https://capturer.readthedocs.io/en/latest/#capturer.CaptureOutput.get_bytes\n.. _get_lines(): https://capturer.readthedocs.io/en/latest/#capturer.CaptureOutput.get_lines\n.. _get_text(): https://capturer.readthedocs.io/en/latest/#capturer.CaptureOutput.get_text\n.. _GitHub: https://github.com/xolox/python-capturer\n.. _gpg: https://en.wikipedia.org/wiki/GNU_Privacy_Guard\n.. _how pytest does it: https://pytest.org/latest/capture.html\n.. _iocapture: https://pypi.python.org/pypi/iocapture\n.. _MIT license: http://en.wikipedia.org/wiki/MIT_License\n.. _per user site-packages directory: https://www.python.org/dev/peps/pep-0370/\n.. _peter@peterodding.com: peter@peterodding.com\n.. _pty.openpty(): https://docs.python.org/2/library/pty.html#pty.openpty\n.. _pty: https://docs.python.org/2/library/pty.html\n.. _PyPI: https://pypi.python.org/pypi/capturer\n.. _pytest: https://pypi.python.org/pypi/pytest\n.. _Read the Docs: https://capturer.readthedocs.io\n.. _ssh: https://en.wikipedia.org/wiki/Secure_Shell\n.. _stderr: https://en.wikipedia.org/wiki/Standard_streams#Standard_error_.28stderr.29\n.. _stdin: https://en.wikipedia.org/wiki/Standard_streams#Standard_input_.28stdin.29\n.. _stdout: https://en.wikipedia.org/wiki/Standard_streams#Standard_output_.28stdout.29\n.. _StringIO: https://docs.python.org/2/library/stringio.html\n.. _sys.stderr: https://docs.python.org/2/library/sys.html#sys.stderr\n.. _sys.stdout: https://docs.python.org/2/library/sys.html#sys.stdout\n.. _the with statement: https://docs.python.org/2/reference/compound_stmts.html#the-with-statement\n.. _virtual environments: http://docs.python-guide.org/en/latest/dev/virtualenvs/\n\n\n", "description_content_type": null, "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://capturer.readthedocs.io", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "capturer", "package_url": "https://pypi.org/project/capturer/", "platform": "", "project_url": "https://pypi.org/project/capturer/", "project_urls": { "Homepage": "https://capturer.readthedocs.io" }, "release_url": "https://pypi.org/project/capturer/2.4/", "requires_dist": [ "humanfriendly (>=2.1)" ], "requires_python": "", "summary": "Easily capture stdout/stderr of the current process and subprocesses", "version": "2.4" }, "last_serial": 2879347, "releases": { "1.0": [ { "comment_text": "", "digests": { "md5": "3a179283de22c49d92cbd88923a15e34", "sha256": "28b8212ae81ad66db342e75304cce1636aa74947012284f892646de9baab92bb" }, "downloads": -1, "filename": "capturer-1.0.tar.gz", "has_sig": false, "md5_digest": "3a179283de22c49d92cbd88923a15e34", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 13237, "upload_time": "2015-06-14T16:19:49", "url": "https://files.pythonhosted.org/packages/46/1c/22fb3ecdbe18750bc0388ffb300db675a316b98263895b8cba0a8a2ce52a/capturer-1.0.tar.gz" } ], "1.1": [ { "comment_text": "", "digests": { "md5": "26c5a594262a6b85a040846d2d760d18", "sha256": "5eba8df5509f50d6db89e5c079f9eba19a1cff30cc5a30c0fa6e698c53c51364" }, "downloads": -1, "filename": "capturer-1.1.tar.gz", "has_sig": false, "md5_digest": "26c5a594262a6b85a040846d2d760d18", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 15281, "upload_time": "2015-06-16T19:47:17", "url": "https://files.pythonhosted.org/packages/d0/a4/3956ab6e08a607fbb6f794e5e42192923b431566502f1fa2e80253eabb7a/capturer-1.1.tar.gz" } ], "2.0": [ { "comment_text": "", "digests": { "md5": "ca55020b50141b308077b6c516e930a2", "sha256": "d56c9ef2d3e3db65025c21a40d2f9b58b49edf2cfcf8ed4945f19d36e426181d" }, "downloads": -1, "filename": "capturer-2.0.tar.gz", "has_sig": false, "md5_digest": "ca55020b50141b308077b6c516e930a2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16832, "upload_time": "2015-06-17T22:49:57", "url": "https://files.pythonhosted.org/packages/80/49/e7692d0e5b80729c6eeebdc88f134ad3a15787ed1b358b42e6efaa39258e/capturer-2.0.tar.gz" } ], "2.1": [ { "comment_text": "", "digests": { "md5": "6a6479ce6246fe80c5dddd9e37fb902f", "sha256": "6837c34651d50615e20281a1cc73a2b363bb7b7c9451003d08ea481a58a6bbb8" }, "downloads": -1, "filename": "capturer-2.1.tar.gz", "has_sig": false, "md5_digest": "6a6479ce6246fe80c5dddd9e37fb902f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17380, "upload_time": "2015-06-21T16:04:13", "url": "https://files.pythonhosted.org/packages/67/d4/b95b8210670ece9c5dcdc14631dd95e6caf11d9e2345ff1dd5752099e8db/capturer-2.1.tar.gz" } ], "2.1.1": [ { "comment_text": "", "digests": { "md5": "e21e872eadbfd9d629767d5627ed5b55", "sha256": "6d892baca28c32ba912d96dfc5d40972090437d7d8d1738453969a0700a272e4" }, "downloads": -1, "filename": "capturer-2.1.1.tar.gz", "has_sig": false, "md5_digest": "e21e872eadbfd9d629767d5627ed5b55", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 17404, "upload_time": "2015-10-24T11:22:15", "url": "https://files.pythonhosted.org/packages/b5/23/35929ea304876f56ea399d902b869d471ae32ca1afda8fee6a29f9df9d11/capturer-2.1.1.tar.gz" } ], "2.2": [ { "comment_text": "", "digests": { "md5": "9a95b8e73dc0d5587477955d11ffb641", "sha256": "9e22ed9ac47c543506a7ce8dce76356ffdd56554a5883f02a7bbe0583c8d375a" }, "downloads": -1, "filename": "capturer-2.2.tar.gz", "has_sig": false, "md5_digest": "9a95b8e73dc0d5587477955d11ffb641", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16804, "upload_time": "2016-10-09T20:04:55", "url": "https://files.pythonhosted.org/packages/5d/dd/3241784dc606e111290b3f2acaf09daa7464551137984e4fb3e9b1043bcf/capturer-2.2.tar.gz" } ], "2.3": [ { "comment_text": "", "digests": { "md5": "dd53b557fc8a2598cbb5042318ad9e4e", "sha256": "99babd915b3fff99b0a38d0253cf7be886f20b7a477e84587d1fd07213f345be" }, "downloads": -1, "filename": "capturer-2.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "dd53b557fc8a2598cbb5042318ad9e4e", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 19325, "upload_time": "2016-11-12T15:53:01", "url": "https://files.pythonhosted.org/packages/47/8e/c12d5d4aff70b51a4c5daffc68191d7075a798b30445312f341e9fac1dc7/capturer-2.3-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "dc95b473eb518f40049023b0fb7d0295", "sha256": "3e4a1edbe96275e33bdf5836fe5c244202bc7acbc675dce73b0f082240cacb69" }, "downloads": -1, "filename": "capturer-2.3.tar.gz", "has_sig": false, "md5_digest": "dc95b473eb518f40049023b0fb7d0295", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 18380, "upload_time": "2016-11-12T15:53:04", "url": "https://files.pythonhosted.org/packages/c2/5a/f155d105eefebe3c044ee7ad3a61c9c91f7ac79c44daff962a064e5fc950/capturer-2.3.tar.gz" } ], "2.4": [ { "comment_text": "", "digests": { "md5": "aac0e6220b3df7b018424eaf4a9a7bfa", "sha256": "2c9d507516e5e86c442ff0c45b08cd0810d314e62bbea7e96ba0f473389d17dc" }, "downloads": -1, "filename": "capturer-2.4-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "aac0e6220b3df7b018424eaf4a9a7bfa", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 19475, "upload_time": "2017-05-17T00:25:37", "url": "https://files.pythonhosted.org/packages/a7/1f/e41ce5ca0410356453f6d5d0102feedc64b9427dc54ee505ff443714b65c/capturer-2.4-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "efca2dc1ea834346bd8f783527b64c23", "sha256": "090142a58f3f85def3a7dd55d9024d0d1a86d1a88aaf9317c0f146244994a615" }, "downloads": -1, "filename": "capturer-2.4.tar.gz", "has_sig": false, "md5_digest": "efca2dc1ea834346bd8f783527b64c23", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16963, "upload_time": "2017-05-17T00:25:39", "url": "https://files.pythonhosted.org/packages/ce/a4/fabb849584366383a59d2ac985a7ece30609f1ae4a40ecfd02baad900a2d/capturer-2.4.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "aac0e6220b3df7b018424eaf4a9a7bfa", "sha256": "2c9d507516e5e86c442ff0c45b08cd0810d314e62bbea7e96ba0f473389d17dc" }, "downloads": -1, "filename": "capturer-2.4-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "aac0e6220b3df7b018424eaf4a9a7bfa", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 19475, "upload_time": "2017-05-17T00:25:37", "url": "https://files.pythonhosted.org/packages/a7/1f/e41ce5ca0410356453f6d5d0102feedc64b9427dc54ee505ff443714b65c/capturer-2.4-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "efca2dc1ea834346bd8f783527b64c23", "sha256": "090142a58f3f85def3a7dd55d9024d0d1a86d1a88aaf9317c0f146244994a615" }, "downloads": -1, "filename": "capturer-2.4.tar.gz", "has_sig": false, "md5_digest": "efca2dc1ea834346bd8f783527b64c23", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 16963, "upload_time": "2017-05-17T00:25:39", "url": "https://files.pythonhosted.org/packages/ce/a4/fabb849584366383a59d2ac985a7ece30609f1ae4a40ecfd02baad900a2d/capturer-2.4.tar.gz" } ] }