8

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" % ???
2
  • if this is a purely "academic" question, why not, but you shouldn't rely on stuff like inspecting stack traces in real life code... instead using custom exception classes (or one of the many built-in ones) is better. Commented Mar 6, 2014 at 18:07
  • Yes it's only was interesting Commented Mar 6, 2014 at 18:43

3 Answers 3

9
import inspect

try:
    foo()
except Exception as e:
    print "Exception raised in %s" % inspect.trace()[-1][3]
Sign up to request clarification or add additional context in comments.

1 Comment

this is probably what the asker meant, but it's probably not the best real life solution :)
7

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.

2 Comments

Yes, it's useful for printing, but when needed to get more info (for example function name) - not suitable
@Habibutsu I updated my answer to show you how traceback is indeed suitable, and can be used to extract function names for example :)
2

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)..."

4 Comments

I agree your approach is better, but its not working for callbacks that you received as is from users. Or for example RPC when TypeError could be raised in attempt to call function or inside of it. Actually now I do not build the logic of relying on this information, but it was interesting.
You could just wrap each callback in code that raises your custom exception.
In this case you lose information about originally exception if only did not include it in the new
Well, if you're on Python 3, you can use exception chaining. The way to do this in Python 2 isn't as nice.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.