2
#! 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.

Community
  • 1
  • 1
iridescent
  • 305
  • 4
  • 14
  • I think erd is accessed before initialization. Can you consider defining the variable or check if it is passed in function call and rerun? – Swadhikar Jul 10 '16 at 12:15
  • `sys.stderr = io.StringIO()`, you should be aware that the error will still be raised so storing in the io object bar you are catching exceptions seems redundant – Padraic Cunningham Jul 10 '16 at 12:22

1 Answers1

7

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
Burhan Khalid
  • 169,990
  • 18
  • 245
  • 284
  • 1
    Thanks for the clarification. I assumed that `redirect_stderr` can allow me to suppress stderr output implicitly. – iridescent Jul 10 '16 at 13:33
  • Where is the variable `args` taken from? (The one used in `sys.__excepthook__`). And do you know if this approach can work from within a jupyter notebook? – Michele Piccolini Feb 05 '20 at 13:08