11

Consider the simple example:

def f():
    try:
        raise TypeError
    except TypeError:
        raise ValueError

f()

I want to catch TypeError object when ValueError is thrown after f() execution. Is it possible to do it?

If I execute function f() then python3 print to stderr all raised exceptions of exception chain (PEP-3134) like

Traceback (most recent call last):
  File "...", line 6, in f
    raise TypeError
TypeError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "...", line 11, in <module>
    f()
  File "...", line 8, in f
    raise ValueError
ValueError

So I would get the list of all exceptions of exception chain or check if exception of some type (TypeError in the above example) exists in exception chain.

1
  • I guess it's an XY Problem. Real question to ask: what exactly are you trying to achieve here (not how you want to achieve that)? Commented Aug 8, 2016 at 9:06

1 Answer 1

23

Python 3 has a beautiful syntactic enhancement on exceptions handling. Instead of plainly raising ValueError, you should raise it from a caught exception, i.e.:

try:
    raise TypeError('Something awful has happened')
except TypeError as e:
    raise ValueError('There was a bad value') from e

Notice the difference between the tracebacks. This one uses raise from version:

Traceback (most recent call last):
  File "/home/user/tmp.py", line 2, in <module>
    raise TypeError('Something awful has happened')
TypeError: Something awful has happened

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/user/tmp.py", line 4, in <module>
    raise ValueError('There was a bad value') from e
ValueError: There was a bad value

Though the result may seem similar, in fact it is rather different! raise from saves the context of the original exception and allows one to trace all the exceptions chain back - which is impossible with simple raise.

To get the original exception, you simply have to refer to new exception's __context__ attribute, i.e.

try:
    try:
        raise TypeError('Something awful has happened')
    except TypeError as e:
        raise ValueError('There was a bad value') from e
except ValueError as e:
    print(e.__context__)
>>> Something awful has happened

Hopefully that is the solution you were looking for.

For more details, see PEP 3134 -- Exception Chaining and Embedded Tracebacks

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks. To get exception objects from caugth ValueError as e need to call: e.__cause__ that returns TypeError object. If the TypeError object (let e2) has cause-exception object then it can be got by e2.__cause__, etc. The generator def cause_gen(exc): yield exc; while exc.__cause__: exc = exc.__cause__; yield exc; returns all exceptions of exception chain where argument is init caught exception.
So is it impossible to get exceptions if they were raised without from (impossible to edit source code)?
Unfortunately not without dirty/hacky code which emulates raise from. If you are bound to Py2, there is a backport in future library. Essentially the PEP was introduced in order to handle the very impossibility of getting the inner exceptions.
In python 3 stderr contains all exceptions of exception chain even if raise from is not used (as it was described in the question). So I think that it's possible to get them in this case. E.g. direct way: parsing stderr output as string. Is there no other way?
@kupgov: I've been searching everywhere for the answer of your exact question, that is, how do I get the original exception object if "raise from" is not used? In my case the exception is generated by an underlying .net dll file, so adding "raise from" is not an option. Did you get an answer in the end?
|

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.