There is a new feature that was introduced in python3 - exception chaining. For some reasons I need to disable it for certain exceptions in my code.
Here is sample co
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
__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
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
__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
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 zero
The 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