Temporarily redirect stdout / stderr

Is it possible to temporarily redirect stdout / stderr in Python (i.e. for the duration of a method)?

Edit:

The problem with the current solutions (which I first remembered, but then forgot) is that they do not redirect; rather, they just completely replace threads. Therefore, if the method has a local copy of one variable for any reason (for example, since the stream was passed as a parameter to something), this will not work.

Any solutions?

+53
redirect python stdout stderr
Jul 22 2018-11-21T00:
source share
9 answers

To solve the problem that some functions can cache the sys.stdout stream as a local variable, and therefore replacing the global sys.stdout will not work inside this function, you can redirect at the file descriptor level ( sys.stdout.fileno() ) for example:

 from __future__ import print_function import os import sys def some_function_with_cached_sys_stdout(stdout=sys.stdout): print('cached stdout', file=stdout) with stdout_redirected(to=os.devnull), merged_stderr_stdout(): print('stdout goes to devnull') some_function_with_cached_sys_stdout() print('stderr also goes to stdout that goes to devnull', file=sys.stderr) print('stdout is back') some_function_with_cached_sys_stdout() print('stderr is back', file=sys.stderr) 

stdout_redirected() redirects all output for sys.stdout.fileno() to a given file name, file object, or file descriptor ( os.devnull in the example).

stdout_redirected() and merged_stderr_stdout() defined here .

+17
Mar 16 '14 at 8:37
source share

You can also put redirection logic in the contextmanager.

 import os import sys class RedirectStdStreams(object): def __init__(self, stdout=None, stderr=None): self._stdout = stdout or sys.stdout self._stderr = stderr or sys.stderr def __enter__(self): self.old_stdout, self.old_stderr = sys.stdout, sys.stderr self.old_stdout.flush(); self.old_stderr.flush() sys.stdout, sys.stderr = self._stdout, self._stderr def __exit__(self, exc_type, exc_value, traceback): self._stdout.flush(); self._stderr.flush() sys.stdout = self.old_stdout sys.stderr = self.old_stderr if __name__ == '__main__': devnull = open(os.devnull, 'w') print('Fubar') with RedirectStdStreams(stdout=devnull, stderr=devnull): print("You'll never see me") print("I'm back!") 
+83
Jul 22 '11 at 10:29
source share

I'm not sure what a temporary redirect means. But you can reassign such threads and reset back.

 temp = sys.stdout sys.stdout = sys.stderr sys.stderr = temp 

Also write in sys.stderr in printed lines like this.

  print >> sys.stderr, "Error in atexit._run_exitfuncs:" 

Normal printing will be output to standard output.

+16
Jul 22 2018-11-21T00:
source share

This is possible with a decorator such as:

 import sys def redirect_stderr_stdout(stderr=sys.stderr, stdout=sys.stdout): def wrap(f): def newf(*args, **kwargs): old_stderr, old_stdout = sys.stderr, sys.stdout sys.stderr = stderr sys.stdout = stdout try: return f(*args, **kwargs) finally: sys.stderr, sys.stdout = old_stderr, old_stdout return newf return wrap 

Use as:

 @redirect_stderr_stdout(some_logging_stream, the_console): def fun(...): # whatever 

or, if you do not want to change the source for fun , call it directly as

 redirect_stderr_stdout(some_logging_stream, the_console)(fun) 

But note that this is not thread safe.

+11
Jul 22 2018-11-21T00:
source share

since python 3.4 there is a contextlib.redirect_stdout context manager:

 from contextlib import redirect_stdout with open('yourfile.txt', 'w') as f: with redirect_stdout(f): # do stuff... 

to completely suppress stdout this works:

 from contextlib import redirect_stdout with redirect_stdout(None): # do stuff... 
+5
Apr 10 '18 at 6:56
source share

Here is the context manager that I found useful. The nice thing is that you can use it with a with statement, as well as handle redirection for child processes.

 import contextlib @contextlib.contextmanager def stdchannel_redirected(stdchannel, dest_filename): """ A context manager to temporarily redirect stdout or stderr eg: with stdchannel_redirected(sys.stderr, os.devnull): ... """ try: oldstdchannel = os.dup(stdchannel.fileno()) dest_file = open(dest_filename, 'w') os.dup2(dest_file.fileno(), stdchannel.fileno()) yield finally: if oldstdchannel is not None: os.dup2(oldstdchannel, stdchannel.fileno()) if dest_file is not None: dest_file.close() 

The context why I created this is in this blog post .

+4
Jul 19 '13 at 17:50
source share

Raymond Hettinger shows us the best way [1]:

 import sys with open(filepath + filename, "w") as f: #replace filepath & filename with f as sys.stdout: print("print this to file") #will be written to filename & -path 

After block with sys.stdout will be reset

[1]: http://www.youtube.com/watch?v=OSGv2VnC0go&list=PLQZM27HgcgT-6D0w6arhnGdSHDcSmQ8r3

+1
Jul 30 '13 at 8:05
source share

We will use the PHP syntax ob_start and ob_get_contents functions in Python3 and redirect the input to the file.

The outputs are stored in a file, any type of stream can also be used.

 from functools import partial output_buffer = None print_orig = print def ob_start(fname="print.txt"): global print global output_buffer print = partial(print_orig, file=output_buffer) output_buffer = open(fname, 'w') def ob_end(): global output_buffer close(output_buffer) print = print_orig def ob_get_contents(fname="print.txt"): return open(fname, 'r').read() 

Application:

 print ("Hi John") ob_start() print ("Hi John") ob_end() print (ob_get_contents().replace("Hi", "Bye")) 

Will print

Hello John Bye John

0
Mar 14 '18 at 8:14
source share
0
Sep 03 '18 at 1:29
source share



All Articles