"Inner Exception" (With Traceback) in Python

Inner exception (with traceback) in Python?

Python 2

It's simple; pass the traceback as the third argument to raise.

import sys
class MyException(Exception): pass

try:
raise TypeError("test")
except TypeError, e:
raise MyException(), None, sys.exc_info()[2]

Always do this when catching one exception and re-raising another.

How to catch and print the full exception traceback without halting/exiting the program?

Some other answer have already pointed out the traceback module.

Please notice that with print_exc, in some corner cases, you will not obtain what you would expect. In Python 2.x:

import traceback

try:
raise TypeError("Oups!")
except Exception, err:
try:
raise TypeError("Again !?!")
except:
pass

traceback.print_exc()

...will display the traceback of the last exception:

Traceback (most recent call last):
File "e.py", line 7, in <module>
raise TypeError("Again !?!")
TypeError: Again !?!

If you really need to access the original traceback one solution is to cache the exception infos as returned from exc_info in a local variable and display it using print_exception:

import traceback
import sys

try:
raise TypeError("Oups!")
except Exception, err:
try:
exc_info = sys.exc_info()

# do you usefull stuff here
# (potentially raising an exception)
try:
raise TypeError("Again !?!")
except:
pass
# end of useful stuff

finally:
# Display the *original* exception
traceback.print_exception(*exc_info)
del exc_info

Producing:

Traceback (most recent call last):
File "t.py", line 6, in <module>
raise TypeError("Oups!")
TypeError: Oups!

Few pitfalls with this though:

  • From the doc of sys_info:

    Assigning the traceback return value to a local variable in a function that is handling an exception will cause a circular reference. This will prevent anything referenced by a local variable in the same function or by the traceback from being garbage collected. [...] If you do need the traceback, make sure to delete it after use (best done with a try ... finally statement)

  • but, from the same doc:

    Beginning with Python 2.2, such cycles are automatically reclaimed when garbage collection is enabled and they become unreachable, but it remains more efficient to avoid creating cycles.


On the other hand, by allowing you to access the traceback associated with an exception, Python 3 produce a less surprising result:

import traceback

try:
raise TypeError("Oups!")
except Exception as err:
try:
raise TypeError("Again !?!")
except:
pass

traceback.print_tb(err.__traceback__)

... will display:

  File "e3.py", line 4, in <module>
raise TypeError("Oups!")

Get exception description and stack trace which caused an exception, all as a string

See the traceback module, specifically the format_exc() function. Here.

import traceback

try:
raise ValueError
except ValueError:
tb = traceback.format_exc()
else:
tb = "No error"
finally:
print tb

In Python how can I raise a custom exception and do a trace back as well?

You don't have to "generate" a traceback, Python takes care of this when you raise an exception (custom or builtin).

Python 2.7.3 (default, Feb 27 2014, 19:58:35) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
pythonrc start
pythonrc done
>>> class MyException(Exception): pass
...
>>> def foo():
... raise MyException("Hey")
...
>>> def bar():
... print "in bar"
... foo()
...
>>> bar()
in bar
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in bar
File "<stdin>", line 2, in foo
__main__.MyException: Hey
>>>

How to catch inner exception in python?

Apparently first I have to catch the outmost exception

Yes.

I do this and then how do I except the one that follows

You can not except the one that follows because you're too late. You can examine the context of the exception you did catch, though. Example:

>>> def foo():
... try:
... errorerror
... except NameError:
... 1/0
...
>>> try:
... foo()
... except ZeroDivisionError as err:
... zerr = err
...
>>> zerr.__context__
NameError("name 'errorerror' is not defined")

When cleaning up after the inner exception, there may be other interesting info for you on the outer exception instance. Look at:

  • the __context__ attribute for implicitly chained exceptions
  • the __cause__ attribute for explicitly chained exceptions
  • the __traceback__ attribute for further context if you need it

See PEP 3134 -- Exception Chaining and Embedded Tracebacks for further details.

How to raise exception in except block without original traceback in python 3.5+

Use raise from None to suppress earlier exceptions:

try:
can_raise_custom_lib_exception()
except custom_lib_exception as e:
cleanup()
raise myOwnException("my own extra text") from None

7.8. The raise statement

[...]

Exception chaining can be explicitly suppressed by specifying None in the from clause:

Nested causes in nested exceptions in python

In Python 3, you can use the from keyword to specify an inner exception:

raise ClientException(...) from ioException

You get a traceback that looks like this:

Traceback (most recent call last):
...
IOException: timeout

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

Traceback (most recent call last):
...
ClientException: couldn't read from client

Python variable scope - outer exception variable undefined if used in inner exception

The block beginning

except Exception as msg:

creates the msg variable at the start of the block, and deletes it at the end of the block. The msg variable that existed already is in the same scope and has the same name, so it is overwritten and then deleted.

You need to use separate names for your two exceptions if you want to track both, because they are in the same scope.

See https://docs.python.org/3/reference/compound_stmts.html#the-try-statement which says:

When an exception has been assigned using as target, it is cleared at the end of the except clause. This is as if

except E as N:
foo

was translated to

except E as N:
try:
foo
finally:
del N


Related Topics



Leave a reply



Submit