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

exception, nested, python, raise

Solution

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 `AlsoFailsError`, replace `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 `raise`:

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

Problem

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?

Original source

Related problems