Creatively... Do!
  • Home
  • Blog
  • Contact
  • Programming
    • Solitaire
    • Minesweeper
    • Sudoku
    • Pong
    • Mandelbrot
  • Music
    • The Snowman

How to globally customize exception stack traces in Python

  • Home
  • Blog
  • How to globally customize exception stack traces in Python
Posted by: christian_abbott 8 years, 10 months ago

(1 comment)

The Python programming language has some useful flexibility which it can take a while to discover. One such example is exceptions. As programmers, we want as much relevant information as we can get when something goes unexpectedly wrong in our programs. When an unhandled exception bubbles up, Python's default behavior is to print a stack trace, the type of error, and an error description. This is printed to sys.stderr (i.e., the console window, typically), like this:

>>> 1/0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

That's dead useful, yes, but perhaps in your program you'd really like to see some other specific data whenever there's a crash. For example, wouldn't it be great to see what the value of your current local variables are? Or the global variables too? Well, don't despair, Python has not left you out in the cold. In fact, the developers made it incredibly easy for you to send whatever you like to sys.stderr using a hook. Whenever an unhandled exception arises, this is the function that Python calls to do the printing:

sys.excepthook(type, value, traceback)

Which takes in these three values:

type:
the exception class, such as ZeroDivisonError
value:
the exception instance that wasn't handled
traceback:
a trackeback object; the same as what is stored in sys.last_traceback

Note: these are the same three ordered values returned by sys.exc_info() during an exception

You can create your own function which takes the same three arguments, make it do what you like, and assign it to the hook:

>>> def my_exchandler(type, value, traceback):
>>>    print("Nothing to see here, folks. Everything's just fine. Move along.", file=sys.stderr)
>>>    # Note: The above is Python 3 code; Python 2's equivalent would look like this
>>>    # print >> sys.stderr, 'Some flippant message'
>>>
>>> import sys
>>> sys.excepthook = my_exchandler
>>>
>>> 1/0
Nothing to see here, folks. Everything's just fine. Move along.

Or, if you wanted to display all the local and global variables as we mentioned before (which is slightly more useful than the above), do this:

>>> import sys, traceback
>>>
>>> def my_exchandler(type, value, tb):
>>>    # Warning: watch for a bit more Python 3-specific code below
>>>    traceback.print_exception(type, value, tb)
>>>    locals = True
>>>    for active_vars in [tb.tb_frame.f_locals, tb.tb_frame.f_globals]:
>>>        header = 'Locals:' if locals else 'Globals:'
>>>        print(header, file=sys.stderr)
>>>        for k, v in active_vars.items():
>>>            if not (k.startswith('__') and k.endswith('__')):
>>>                print('\t{} = {}'.format(k, v), file=sys.stderr)
>>>        locals = False
>>>
>>> sys.excepthook = my_exchandler
>>>
>>> my_var = 'suspicious value here?'
>>>
>>> 1/0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
Locals:
	my_var = 'suspicious value here?'
	traceback = <module 'traceback' from '/usr/lib/python3.2/traceback.pyc'>
	my_exchandler = <function my_exchandler at 0x89f895c>
	sys= <module 'sys' (built-in)>
Globals:
	my_var = 'suspicious value here?'
	traceback = <module 'traceback' from '/usr/lib/python2.7/traceback.pyc'>
	my_exchandler= <function my_exchandler at 0x89f895c>
	sys= <module 'sys' (built-in)>

Nice! But what happens then if you want the default behavior back, or if you completely mess up your replacement exception function and it produces an exception itself? Not to worry, Python kept a backup copy of the default hook the entire time, and uses it when needed. It's here:

sys.__excepthook__

You can use the backup copy to get back to the default behavior:

>>> sys.excepthook = sys.__excepthook__
Current rating: 3.4
Share on Twitter Share on Facebook
  • ← Is your tango embrace really too firm or too relaxed?
  • How to make iterators out of Python functions without using yield →

Comments

Adam Groszer 6 years, 10 months ago

see the zope.exceptions package for a neat print_exception replacement

Link | Reply
Current rating: 1.8

required

required (not published)

required

required

New Comment

required

required (not published)

required

required

Recent Posts

  • Using SVG and CSS to create Pacman (out of pie charts)
  • How to solve the Impossible Escape puzzle with almost no math
  • How to make iterators out of Python functions without using yield
  • How to globally customize exception stack traces in Python
  • Is your tango embrace really too firm or too relaxed?

Archive

2017
  • May (1)
2015
  • February (1)
2013
  • November (1)
  • October (1)
  • March (1)
  • February (3)
  • January (4)
2012
  • December (1)

Categories

  • django (2)
  • environment (1)
  • math (2)
  • python (2)
  • tango (5)
  • web development (1)

Authors

  • christian_abbott (13)

Feeds

RSS / Atom
  • Blog
  • Contact
  • Programming
  • Music
©2012-2020 Christian Abbott