https://github.com/bskinn/stdio-mgr
Context manager for mocking/wrapping stdin/stdout/stderr
https://github.com/bskinn/stdio-mgr
context-manager mocking python3 stderr stdin stdout
Last synced: 9 months ago
JSON representation
Context manager for mocking/wrapping stdin/stdout/stderr
- Host: GitHub
- URL: https://github.com/bskinn/stdio-mgr
- Owner: bskinn
- License: mit
- Created: 2018-03-24T17:06:12.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2024-09-26T03:33:02.000Z (over 1 year ago)
- Last Synced: 2025-03-23T18:54:16.711Z (12 months ago)
- Topics: context-manager, mocking, python3, stderr, stdin, stdout
- Language: Python
- Homepage:
- Size: 154 KB
- Stars: 14
- Watchers: 3
- Forks: 4
- Open Issues: 45
-
Metadata Files:
- Readme: README.rst
- Changelog: CHANGELOG.md
- License: LICENSE.txt
Awesome Lists containing this project
README
stdio Manager: Context manager for mocking/wrapping ``stdin``/``stdout``/``stderr``
===================================================================================
**Current Development Version:**
.. image:: https://travis-ci.org/bskinn/stdio-mgr.svg?branch=master
:target: https://travis-ci.org/bskinn/stdio-mgr
.. image:: https://codecov.io/gh/bskinn/stdio-mgr/branch/master/graph/badge.svg
:target: https://codecov.io/gh/bskinn/stdio-mgr
**Most Recent Stable Release:**
.. image:: https://img.shields.io/pypi/v/stdio_mgr.svg
:target: https://pypi.org/project/stdio-mgr
.. image:: https://img.shields.io/pypi/pyversions/stdio-mgr.svg
**Info:**
.. image:: https://img.shields.io/github/license/mashape/apistatus.svg
:target: https://github.com/bskinn/stdio-mgr/blob/stable/LICENSE.txt
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/ambv/black
----
**Have a CLI Python application?**
**Want to automate testing of the actual console input & output
of your user-facing components?**
`stdio Manager` can help.
While some functionality here is more or less duplicative of
``redirect_stdout`` and ``redirect_stderr`` in ``contextlib``
`within the standard library `__,
it provides (i) a much more concise way to mock both ``stdout`` and ``stderr`` at the same time,
and (ii) a mechanism for mocking ``stdin``, which is not available in ``contextlib``.
**First, install:**
.. code::
$ pip install stdio-mgr
Then use!
All of the below examples assume ``stdio_mgr`` has already
been imported via:
.. code::
>>> from stdio_mgr import stdio_mgr
**Mock** ``stdout``\ **:**
.. code::
>>> with stdio_mgr() as (in_, out_, err_):
... print('foobar')
... out_cap = out_.getvalue().replace(os.linesep, '\n')
>>> out_cap
'foobar\n'
>>> in_.closed and out_.closed and err_.closed
True
By default ``print``
`appends a newline `__
after each argument, which is why ``out_cap`` is ``'foobar\n'``
and not just ``'foobar'``.
As currently implemented, ``stdio_mgr`` closes all three mocked streams
upon exiting the managed context.
**Mock** ``stderr``\ **:**
.. code ::
>>> import warnings
>>> with stdio_mgr() as (in_, out_, err_):
... warnings.warn("foo has no bar")
... err_cap = err_.getvalue().replace(os.linesep, '\n')
>>> err_cap
'...UserWarning: foo has no bar\n...'
**Mock** ``stdin``\ **:**
The simulated user input has to be pre-loaded to the mocked stream.
**Be sure to include newlines in the input to correspond to
each mocked** `Enter` **keypress!**
Otherwise, ``input`` will hang, waiting for a newline
that will never come.
If the entirety of the input is known in advance,
it can just be provided as an argument to ``stdio_mgr``.
Otherwise, ``.append()`` mocked input to ``in_``
within the managed context as needed:
.. code::
>>> with stdio_mgr('foobar\n') as (in_, out_, err_):
... print('baz')
... in_cap = input('??? ')
...
... _ = in_.append(in_cap[:3] + '\n')
... in_cap2 = input('??? ')
...
... out_cap = out_.getvalue().replace(os.linesep, '\n')
>>> in_cap
'foobar'
>>> in_cap2
'foo'
>>> out_cap
'baz\n??? foobar\n??? foo\n'
The ``_ =`` assignment suppresses ``print``\ ing of the return value
from the ``in_.append()`` call--otherwise, it would be interleaved
in ``out_cap``, since this example is shown for an interactive context.
For non-interactive execution, as with ``unittest``, ``pytest``, etc.,
these 'muting' assignments should not be necessary.
**Both** the ``'??? '`` prompts for ``input``
**and** the mocked input strings
are echoed to ``out_``, mimicking what a CLI user would see.
A subtlety: While the trailing newline on, e.g., ``'foobar\n'`` is stripped
by ``input``, it is *retained* in ``out_``.
This is because ``in_`` tees the content read from it to ``out_``
*before* that content is passed to ``input``.
**Want to modify internal** ``print`` **calls
within a function or method?**
In addition to mocking, ``stdio_mgr`` can also be used to
wrap functions that directly output to ``stdout``/``stderr``. A ``stdout`` example:
.. code::
>>> def emboxen(func):
... def func_wrapper(s):
... from stdio_mgr import stdio_mgr
...
... with stdio_mgr() as (in_, out_, err_):
... func(s)
... content = out_.getvalue()
...
... max_len = max(map(len, content.splitlines()))
... fmt_str = '| {{: <{0}}} |\n'.format(max_len)
...
... newcontent = '=' * (max_len + 4) + '\n'
... for line in content.splitlines():
... newcontent += fmt_str.format(line)
... newcontent += '=' * (max_len + 4)
...
... print(newcontent)
...
... return func_wrapper
>>> @emboxen
... def testfunc(s):
... print(s)
>>> testfunc("""\
... Foo bar baz quux.
... Lorem ipsum dolor sit amet.""")
===============================
| Foo bar baz quux. |
| Lorem ipsum dolor sit amet. |
===============================
----
Available on `PyPI `__
(``pip install stdio-mgr``).
Source on `GitHub `__. Bug reports
and feature requests are welcomed at the
`Issues `__ page there.
Copyright \(c) 2018-2019 Brian Skinn
License: The MIT License. See `LICENSE.txt `__
for full license terms.