Created
July 20, 2013 01:34
-
-
Save msabramo/6043474 to your computer and use it in GitHub Desktop.
An experiment with creating a context manager that can temporarily redirect stdout and stderr - for http://bugs.python.org/issue15805
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import contextlib | |
import os | |
import sys | |
@contextlib.contextmanager | |
def redirected(**kwargs): | |
""" | |
A context manager to temporarily redirect stdout or stderr | |
Examples: | |
# Redirect stdout to /dev/null | |
>>> with redirected(stdout=None): | |
... os.system("echo foo; ls dfkdjfdkfd") | |
... | |
ls: dfkdjfdkfd: No such file or directory | |
# Redirect stderr to /dev/null | |
>>> with redirected(stderr=None): | |
... os.system("echo foo; ls djdffdd") | |
... | |
foo | |
256 | |
# Redirect stdout and stderr to /dev/null | |
>>> with redirected(stdout=None, stderr=None): | |
... os.system("echo foo; ls djdffdd") | |
... | |
# Redirect stdout and stderr to filenames | |
>>> with redirected(stdout='stuff_stdout.txt', stderr='stuff_stderr.txt'): | |
... ret = os.system("echo foo; ls dfjkdfd") | |
... | |
>>> open('stuff_stdout.txt').read() | |
'foo\n' | |
>>> open('stuff_stderr.txt').read() | |
'ls: dfjkdfd: No such file or directory\n' | |
# Redirect stdout to a file and stderr to a filename | |
>>> with open('going_to_stdout.txt', 'w') as out: | |
... with redirected(stdout=out, stderr='stuff_stderr.txt'): | |
... ret = os.system("echo stuff going to stdout; ls 123456") | |
... | |
>>> open('going_to_stdout.txt', 'r').read() | |
'stuff going to stdout\n' | |
>>> open('stuff_stderr.txt', 'r').read() | |
'ls: 123456: No such file or directory\n' | |
# Redirect stdout to a file-like object | |
# This does not work with subprocesses. | |
>>> from StringIO import StringIO | |
>>> out = StringIO() | |
>>> with redirected(stdout=out): | |
... print('printing some stuff') | |
... | |
>>> out.getvalue() | |
'printing some stuff\n' | |
""" | |
dest_files = {} | |
old_filenos = {} | |
try: | |
for channel_name, destination in kwargs.items(): | |
stdchannel = getattr(sys, channel_name) | |
old_filenos[channel_name] = os.dup(stdchannel.fileno()) | |
dest_file = None | |
if destination is None: | |
dest_file = open(os.devnull, 'w') | |
elif hasattr(destination, 'startswith'): # A string => treat as filename | |
dest_file = open(destination, 'w') | |
elif hasattr(destination, 'fileno'): # A file-like object | |
dest_file = destination | |
else: | |
setattr(sys, channel_name, destination) | |
if dest_file: | |
os.dup2(dest_file.fileno(), stdchannel.fileno()) | |
dest_files[channel_name] = dest_file | |
yield | |
finally: | |
for channel_name, old_fileno in old_filenos.items(): | |
setattr(sys, '%s' % channel_name, getattr(sys, '__%s__' % channel_name)) | |
if channel_name in dest_files: | |
stdchannel = getattr(sys, channel_name) | |
dest_file = dest_files[channel_name] | |
if old_fileno is not None: | |
os.dup2(old_fileno, stdchannel.fileno()) | |
if dest_file is not None: | |
dest_file.close() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
An experiment for http://bugs.python.org/issue15805