Habibutsu
Habibutsu

Reputation: 622

How in Python find where exception was raised

How to determine in what function exception was raised. For example exist two functions: 'foo' and 'bar'. In 'foo' exception will raised randomly.

import random


def foo():
    if random.randint(1, 10) % 2:
        raise Exception
    bar()


def bar():
    raise Exception

try:
    foo()
except Exception as e:
    print "Exception raised in %s" % ???

Upvotes: 8

Views: 6629

Answers (3)

Morten Jensen
Morten Jensen

Reputation: 5936

I use the traceback module, like so:

import traceback

try:
    1 / 0
except Exception:
    print traceback.format_exc()

This gives the following output:

Traceback (most recent call last):
  File "<ipython-input-3-6b05b5b621cb>", line 2, in <module>
    1 / 0
ZeroDivisionError: integer division or modulo by zero

If the code runs from a file, the traceback will tell the line and character number of where the error occured :)

EDIT:

To accomodate the comment from Habibutsu: Yes, it's useful for printing, but when needed to get more info (for example function name) - not suitable

The doc-pages tell you how to extract the trace programmatically: http://docs.python.org/2/library/traceback.html

From the page linked above:

>>> import traceback
>>> def another_function():
...     lumberstack()
...
>>> def lumberstack():
...     traceback.print_stack()
...     print repr(traceback.extract_stack())
...     print repr(traceback.format_stack())
...
>>> another_function()
  File "<doctest>", line 10, in <module>
    another_function()
  File "<doctest>", line 3, in another_function
    lumberstack()
  File "<doctest>", line 6, in lumberstack
    traceback.print_stack()
[('<doctest>', 10, '<module>', 'another_function()'),
 ('<doctest>', 3, 'another_function', 'lumberstack()'),
 ('<doctest>', 7, 'lumberstack', 'print repr(traceback.extract_stack())')]
['  File "<doctest>", line 10, in <module>\n    another_function()\n',
 '  File "<doctest>", line 3, in another_function\n    lumberstack()\n',
 '  File "<doctest>", line 8, in lumberstack\n    print repr(traceback.format_stack())\n']

The doc-string for traceback.extract_stack is the same as for traceback.extract_tb

traceback.extract_tb(traceback[, limit])

Return a list of up to limit “pre-processed” stack trace entries extracted from the traceback object traceback. It is useful for alternate formatting of stack traces. If limit is omitted or None, all entries are extracted. A “pre-processed” stack trace entry is a quadruple (filename, line number, function name, text) representing the information that is usually printed for a stack trace. The text is a string with leading and trailing whitespace stripped; if the source is not available it is None.

Upvotes: 7

jme
jme

Reputation: 20695

What is your goal? If you are worried about bar and foo throwing the same exception type and the caller not being able to differentiate between them, just derive a new exception class:

import random

class FooException(Exception):
    """An exception thrown only by foo."""

def foo():
    if random.randint(1,10) % 2:
        raise FooException

    bar()

def bar():
    raise Exception

try:
    foo()
except FooException:
    print "Exception raised in foo..."
except:
    print "Exception raised in bar (probably)..."

Upvotes: 2

Habibutsu
Habibutsu

Reputation: 622

import inspect

try:
    foo()
except Exception as e:
    print "Exception raised in %s" % inspect.trace()[-1][3]

Upvotes: 9

Related Questions