I know that if I want to re-raise an exception, I simple use
raise without arguments in the respective
except block. But given a nested expression like
try: something() except SomeError as e: try: plan_B() except AlsoFailsError: raise e # I'd like to raise the SomeError as if plan_B() # didn't raise the AlsoFailsError
how can I re-raise the
SomeError without breaking the stack trace?
raise alone would in this case re-raise the more recent
AlsoFailsError. Or how could I refactor my code to avoid this issue?
As of Python 3, the traceback is stored in the exception, so a simple
raise e will do the (mostly) right thing:
try: something() except SomeError as e: try: plan_B() except AlsoFailsError: raise e # or raise e from None - see below
The traceback produced will include an additional notice that
SomeError occurred while handling
AlsoFailsError (because of
raise e being inside
except AlsoFailsError). This is misleading because what actually happened is the other way around – we encountered
AlsoFailsError, and handled it, while trying to recover from
SomeError. To obtain a traceback that doesn’t include
raise e with
raise e from None.
In Python 2 you’d store the exception type, value, and traceback in local variables and use the three-argument form of
try: something() except SomeError: t, v, tb = sys.exc_info() try: plan_B() except AlsoFailsError: raise t, v, tb
try: s = something() except SomeError as e: def wrapped_plan_B(): try: return False, plan_B() except: return True, None failed, s = wrapped_plan_B() if failed: raise
Python 3.5+ attaches the traceback information to the error anyway, so it’s no longer necessary to save it separately.
>>> def f(): ... try: ... raise SyntaxError ... except Exception as e: ... err = e ... try: ... raise AttributeError ... except Exception as e1: ... raise err from None >>> f() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 9, in f File "<stdin>", line 3, in f SyntaxError: None >>>
six.reraise(exc_type, exc_value, exc_traceback=None)
Reraise an exception, possibly with a different traceback.
So, you can write:
import six try: something() except SomeError: t, v, tb = sys.exc_info() try: plan_B() except AlsoFailsError: six.reraise(t, v, tb)