Issue #15805: Add contextlib.redirect_stdout()
This commit is contained in:
parent
5ed3bc9adb
commit
088cbf2d39
|
@ -115,6 +115,37 @@ Functions and classes provided:
|
||||||
|
|
||||||
.. versionadded:: 3.4
|
.. versionadded:: 3.4
|
||||||
|
|
||||||
|
.. function:: redirect_stdout(new_target)
|
||||||
|
|
||||||
|
Context manager for temporarily redirecting :data:`sys.stdout` to
|
||||||
|
another file or file-like object.
|
||||||
|
|
||||||
|
This tool adds flexibility to existing functions or classes whose output
|
||||||
|
is hardwired to stdout.
|
||||||
|
|
||||||
|
For example, the output of :func:`help` normally is sent to *sys.stdout*.
|
||||||
|
You can capture that output in a string by redirecting the output to a
|
||||||
|
:class:`io.StringIO` object::
|
||||||
|
|
||||||
|
f = io.StringIO()
|
||||||
|
with redirect_stdout(f):
|
||||||
|
help(pow)
|
||||||
|
s = f.getvalue()
|
||||||
|
|
||||||
|
To send the output of :func:`help` to a file on disk, redirect the output
|
||||||
|
to a regular file::
|
||||||
|
|
||||||
|
with open('help.txt', 'w') as f:
|
||||||
|
with redirect_stdout(f):
|
||||||
|
help(pow)
|
||||||
|
|
||||||
|
To send the output of :func:`help` to *sys.stderr*::
|
||||||
|
|
||||||
|
with redirect_stdout(sys.stderr):
|
||||||
|
help(pow)
|
||||||
|
|
||||||
|
.. versionadded:: 3.4
|
||||||
|
|
||||||
.. class:: ContextDecorator()
|
.. class:: ContextDecorator()
|
||||||
|
|
||||||
A base class that enables a context manager to also be used as a decorator.
|
A base class that enables a context manager to also be used as a decorator.
|
||||||
|
|
|
@ -4,7 +4,8 @@ import sys
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
__all__ = ["contextmanager", "closing", "ContextDecorator", "ExitStack", "ignored"]
|
__all__ = ["contextmanager", "closing", "ContextDecorator", "ExitStack",
|
||||||
|
"ignored", "redirect_stdout"]
|
||||||
|
|
||||||
|
|
||||||
class ContextDecorator(object):
|
class ContextDecorator(object):
|
||||||
|
@ -140,6 +141,43 @@ class closing(object):
|
||||||
def __exit__(self, *exc_info):
|
def __exit__(self, *exc_info):
|
||||||
self.thing.close()
|
self.thing.close()
|
||||||
|
|
||||||
|
class redirect_stdout:
|
||||||
|
"""Context manager for temporarily redirecting stdout to another file
|
||||||
|
|
||||||
|
# How to send help() to stderr
|
||||||
|
|
||||||
|
with redirect_stdout(sys.stderr):
|
||||||
|
help(dir)
|
||||||
|
|
||||||
|
# How to write help() to a file
|
||||||
|
|
||||||
|
with open('help.txt', 'w') as f:
|
||||||
|
with redirect_stdout(f):
|
||||||
|
help(pow)
|
||||||
|
|
||||||
|
# How to capture disassembly to a string
|
||||||
|
|
||||||
|
import dis
|
||||||
|
import io
|
||||||
|
|
||||||
|
f = io.StringIO()
|
||||||
|
with redirect_stdout(f):
|
||||||
|
dis.dis('x**2 - y**2')
|
||||||
|
s = f.getvalue()
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, new_target):
|
||||||
|
self.new_target = new_target
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self.old_target = sys.stdout
|
||||||
|
sys.stdout = self.new_target
|
||||||
|
return self.new_target
|
||||||
|
|
||||||
|
def __exit__(self, exctype, excinst, exctb):
|
||||||
|
sys.stdout = self.old_target
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def ignored(*exceptions):
|
def ignored(*exceptions):
|
||||||
"""Context manager to ignore specified exceptions
|
"""Context manager to ignore specified exceptions
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"""Unit tests for contextlib.py, and other context managers."""
|
"""Unit tests for contextlib.py, and other context managers."""
|
||||||
|
|
||||||
|
import io
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
@ -653,6 +654,14 @@ class TestIgnored(unittest.TestCase):
|
||||||
with ignored(LookupError):
|
with ignored(LookupError):
|
||||||
'Hello'[50]
|
'Hello'[50]
|
||||||
|
|
||||||
|
class TestRedirectStdout(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_redirect_to_string_io(self):
|
||||||
|
f = io.StringIO()
|
||||||
|
with redirect_stdout(f):
|
||||||
|
help(pow)
|
||||||
|
s = f.getvalue()
|
||||||
|
self.assertIn('pow', s)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -32,6 +32,8 @@ Library
|
||||||
- Issue #19158: a rare race in BoundedSemaphore could allow .release() too
|
- Issue #19158: a rare race in BoundedSemaphore could allow .release() too
|
||||||
often.
|
often.
|
||||||
|
|
||||||
|
- Issue #15805: Add contextlib.redirect_stdout().
|
||||||
|
|
||||||
- Issue #18716: Deprecate the formatter module.
|
- Issue #18716: Deprecate the formatter module.
|
||||||
|
|
||||||
- Issue #18037: 2to3 now escapes '\u' and '\U' in native strings.
|
- Issue #18037: 2to3 now escapes '\u' and '\U' in native strings.
|
||||||
|
|
Loading…
Reference in New Issue