]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #15805: Add contextlib.redirect_stdout()
authorRaymond Hettinger <python@rcn.com>
Thu, 10 Oct 2013 07:46:57 +0000 (00:46 -0700)
committerRaymond Hettinger <python@rcn.com>
Thu, 10 Oct 2013 07:46:57 +0000 (00:46 -0700)
Doc/library/contextlib.rst
Lib/contextlib.py
Lib/test/test_contextlib.py
Misc/NEWS

index 349b805f3d902cb7ade797ddcfeb3c99a77f0213..4b86755bad74c8e075b47414b768952f5f7555e0 100644 (file)
@@ -115,6 +115,37 @@ Functions and classes provided:
 
    .. 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()
 
    A base class that enables a context manager to also be used as a decorator.
index aaab0953bdf25386e4cb4e8fee9fac4775ec66c4..868fa6c43d77088d0f6e9fa327330f5fb8828324 100644 (file)
@@ -4,7 +4,8 @@ import sys
 from collections import deque
 from functools import wraps
 
-__all__ = ["contextmanager", "closing", "ContextDecorator", "ExitStack", "ignored"]
+__all__ = ["contextmanager", "closing", "ContextDecorator", "ExitStack",
+           "ignored", "redirect_stdout"]
 
 
 class ContextDecorator(object):
@@ -140,6 +141,43 @@ class closing(object):
     def __exit__(self, *exc_info):
         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
 def ignored(*exceptions):
     """Context manager to ignore specified exceptions
index 28929175a628d45d3169311a08696837b049d110..d8a0530689eb787ee5d5991fe423b92042073d39 100644 (file)
@@ -1,5 +1,6 @@
 """Unit tests for contextlib.py, and other context managers."""
 
+import io
 import sys
 import tempfile
 import unittest
@@ -653,6 +654,14 @@ class TestIgnored(unittest.TestCase):
         with ignored(LookupError):
             '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__":
     unittest.main()
index 4d78be684ae5bfd747551ee0491d197f673ce74b..04132c66a52725e36754d8f5e4cbb8ff864b6ceb 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -32,6 +32,8 @@ Library
 - Issue #19158:  a rare race in BoundedSemaphore could allow .release() too
   often.
 
+- Issue #15805: Add contextlib.redirect_stdout().
+
 - Issue #18716: Deprecate the formatter module.
 
 - Issue #18037: 2to3 now escapes '\u' and '\U' in native strings.