Disable exception chaining in python 3 Disable exception chaining in python 3 python-3.x python-3.x

Disable exception chaining in python 3


Simple Answer

try:    print(10/0)except ZeroDivisionError as e:    raise AssertionError(str(e)) from None

However, you probably actually want:

try:    print(10/0)except ZeroDivisionError as e:    raise AssertionError(str(e)) from e

Explanation

__cause__

Implicit exception chaining happens through __context__ when there isn't an explicit cause exception set.

Explicit exception chaining works through __cause__ so if you set __cause__ to the exception itself, it should stop the chaining. If __cause__ is set, Python will suppress the implicit message.

try:    print(10/0)except ZeroDivisionError as e:    exc = AssertionError(str(e))    exc.__cause__ = exc    raise exc

raise from

We can use "raise from" to do the same thing:

try:    print(10/0)except ZeroDivisionError as e:    exc = AssertionError(str(e))    raise exc from exc

None __cause__

Setting __cause__ to None actually does the same thing:

try:    print(10/0)except ZeroDivisionError as e:    exc = AssertionError(str(e))    exc.__cause__ = None    raise exc

raise from None

So that brings us to the most elegant way to do this which is to raise from None:

try:    print(10/0)except ZeroDivisionError as e:    raise AssertionError(str(e)) from None

But I would argue that you usually want to explicitly raise your exception from the cause exception so the traceback is preserved:

try:    print(10/0)except ZeroDivisionError as e:    raise AssertionError(str(e)) from e

This will give us a slightly different message that states that the first exception was the direct cause of the second:

Traceback (most recent call last):  File "<stdin>", line 2, in <module>ZeroDivisionError: division by zeroThe above exception was the direct cause of the following exception:Traceback (most recent call last):  File "<stdin>", line 4, in <module>AssertionError: division by zero