PyMOTW: sys, Part 4: Exception Handling

By Doug Hellmann
November 1, 2009

Exception Handling

sys includes features for trapping and working with exceptions.

Unhandled Exceptions

Many applications are structured with a main loop that wraps execution in a global exception handler to trap errors not handled at a lower level. Another way to achieve the same thing is by setting the sys.excepthook to a function that takes three arguments (error type, error value, and traceback) and let it deal with unhandled errors.

import sys

def my_excepthook(type, value, traceback):
    print 'Unhandled error:', type, value

sys.excepthook = my_excepthook

print 'Before exception'

raise RuntimeError('This is the error message')

print 'After exception'

Since there is no try:except block around the line where the exception is raised the following print statement is not run, even though the except hook is set.

$ python sys_excepthook.py
Before exception
Unhandled error: <type 'exceptions.RuntimeError'> This is the error message

Current Exception

There are times when an explicit exception handler is preferred, either for code clarity or to avoid conflicts with libraries that try to install their own excepthook. In these cases you may want to write a common handler function, but avoid passing the exception object to it explicitly. You can get the current exception for a thread by calling exc_info().

The return value of exc_info() is a three member tuple containing the exception class, an exception instance, and a traceback. Using exc_info() is preferred over the old form (with exc_type, exc_value, and exc_traceback) because it is thread-safe.

import sys
import threading
import time

def do_something_with_exception():
    exc_type, exc_value = sys.exc_info()[:2]
    print 'Handling %s exception with message "%s" in %s' % \
        (exc_type.__name__, exc_value, threading.current_thread().name)

def cause_exception(delay):
    time.sleep(delay)
    raise RuntimeError('This is the error message')

def thread_target(delay):
    try:
        cause_exception(delay)
    except:
        do_something_with_exception()

threads = [ threading.Thread(target=thread_target, args=(0.3,)),
            threading.Thread(target=thread_target, args=(0.1,)),
            ]
for t in threads:
    t.start()
for t in threads:
    t.join()

Note

This example avoids introducing a circular reference between the traceback and a local variable in the current frame by ignoring that part of the return value from exc_info(). If you do need the traceback for some reason (such as to log it), you should explicitly delete the local variable when you’re done (using del) to avoid cycles.

$ python sys_exc_info.py
Handling RuntimeError exception with message "This is the error message" in Thread-2
Handling RuntimeError exception with message "This is the error message" in Thread-1

Previous Interactive Exception

In the interactive interpreter, there is only one thread of interaction. Unhandled exceptions in that thread are saved to three variables in sys (last_type, last_value, and last_traceback) to make it easy to retrieve them for debugging. With the post-mortem debugger in pdb you don’t have to use the values directly.

$ python
Python 2.6.2 (r262:71600, Apr 16 2009, 09:17:39)
[GCC 4.0.1 (Apple Computer, Inc. build 5250)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def cause_exception():
...   raise RuntimeError('This is the error message')
...
>>> cause_exception()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in cause_exception
RuntimeError: This is the error message
>>> import pdb
>>> pdb.pm()
> <stdin>(2)cause_exception()
(Pdb) where
  <stdin>(1)<module>()
> <stdin>(2)cause_exception()
(Pdb)

See also

exceptions
Built-in errors
pdb
Python debugger
traceback
Module for working with tracebacks.

PyMOTW Home

The canonical version of this article


You might also be interested in:

News Topics

Recommended for You

Got a Question?