Disable exception chaining in python 3

A new feature has been introduced that was introduced in python3 - the exception chain. For some reason, I need to disable it for some exceptions in my code.

Here is a sample code:

try: print(10/0) except ZeroDivisionError as e: sys.exc_info() raise AssertionError(str(e)) 

what do I see:

 Traceback (most recent call last): File "draft.py", line 19, in main print(10/0) ZeroDivisionError: division by zero During handling of the above exception, another exception occurred: Traceback (most recent call last): File "draft.py", line 26, in <module> main() File "draft.py", line 22, in main raise AssertionError(str(e)) AssertionError: division by zero 

what i want to see:

 Traceback (most recent call last): File "draft.py", line 26, in <module> main() File "draft.py", line 22, in main raise AssertionError(str(e)) AssertionError: division by zero 

I tried using sys.exc_clear() , but this mehtod is also removed from python 3. I can use a workaround that works

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

but I think there is a better solution.

+8
python exception-handling
source share
1 answer

Simple answer

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

However, you probably really want to:

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

Explanation

__cause__

An implicit exception chain occurs through __context__ when there is no explicit set of cause exceptions.

An explicit exception chain works through __cause__ , so if you set __cause__ for the exception itself, it should stop the chain. If __cause__ 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 out

We can use "raise out" to do the same:

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

No __cause__

Setting __cause__ to None does the same:

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

raise out of none

So, this leads us to the most elegant way to do this to boost with None :

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

But I would say that you usually want to explicitly raise your exception from the reason exception in order to keep the trace:

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

This will give us a slightly different message saying 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 
+12
source share

All Articles