How to re-create an exception in nested try / except blocks?

I know that if I want to re-create an exception, I simply use raise with no arguments in the corresponding 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 SomeError without breaking the stack trace? Only raise in this case will raise a later AlsoFailsError . Or how can I reorganize my code to avoid this problem?

+77
python exception nested raise
Aug 12 '13 at
source share
4 answers

You can store the exception type, value, and tracker in local variables and use the raise three-argument of the form :

 try: something() except SomeError: t, v, tb = sys.exc_info() try: plan_B() except AlsoFailsError: raise t, v, tb 

In Python 3, tracing is saved in an exception, so raise e will do the (mostly) right thing:

 try: something() except SomeError as e: try: plan_B() except AlsoFailsError: raise e 

The only problem with the above is that it will produce a slightly misleading tracker that tells you that SomeError occurred during the processing of AlsoFailsError (due to raise e inside, except AlsoFailsError ), where the exact opposite actually happened - we pumped AlsoFailsError trying to recover from SomeError . To disable this behavior and get AlsoFailsError , which AlsoFailsError is never mentioned AlsoFailsError , replace raise e with raise e from None .

+91
Aug 12 '13 at 13:47 on
source share

Even if the decision made is correct, it would be nice to point to the Six library , which has a Python 2 + 3 solution using six.reraise .

six. reraise (exc_type, exc_value, exc_traceback = none)

Throw an exception, possibly with a different trace. [...]

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) 
+15
Sep 28 '17 at 10:27
source share

As suggested by Drew McGowan , but taking care of the general case (where the return value of s present), here's an alternative to user4815162342 answer :

 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 
+9
Aug 12 '13 at 14:10
source share

Python 3. 5+ appends trace information to the error anyway, so there is no longer any need to keep it separate.

 >>> 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 >>> 
+4
Apr 25 '17 at 8:25
source share



All Articles