Search code examples
pythonpython-3.xstdstderr

redirect_stderr does not work (Python 3.5)


#! python3
from contextlib import redirect_stderr
import io

f = io.StringIO()
with redirect_stderr(f):
    # simulates an error
    erd

As seen above, I have used the redirect_stderr function to redirect stderr to a StringIO object. However, it doesn't work, as the error message is still printed out in command prompt:

Traceback (most recent call last):
  File "C:\Users\max\testerr.py", line 8, in <module>
    erd
NameError: name 'erd' is not defined

I tested it on Python 3.5.1 64 bit and 3.5.2 64 bit with the same results.

A similar issue in this thread

I have also tried writing the error to a file as described in the linked thread, but the file is empty after running the script.


Solution

  • You need to actually write to stderr, it is not a tool to catch exceptions.

    >>> from contextlib import redirect_stderr
    >>> import io
    >>> f = io.StringIO()
    >>> import sys
    >>> with redirect_stderr(f):
    ...    print('Hello', file=sys.stderr)
    ...
    >>> f.seek(0)
    0
    >>> f.read()
    'Hello\n'
    

    To catch exceptions, you need to do some more work. You can use a logging library (external), or write your own exception handler, and then use your custom output for it.

    Here is something quick, which uses a logger instance to help write to the stream:

    log = logging.getLogger('TEST')
    log.addHandler(logging.StreamHandler(stream=f))
    
    def exception_handler(exc_type, exc_value, exc_traceback):
        if issubclass(exc_type, KeyboardInterrupt):
           # Let the system handle things like CTRL+C
           sys.__excepthook__(*args)
        log.error('Exception: ', exc_info=(exc_type, exc_value, exc_traceback))
    
    sys.excepthook = exception_handler
    raise RuntimeError('foo')
    

    Here f is the same StringIO instance from above. After you run this code, you should not see any traceback on your console, but it will be stored in the stream object:

    >>> f.seek(0)
    0
    >>> print(f.read())
    Hello
    Exception:
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    RuntimeError: foo