Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disable exception chaining in python 3

Tags:

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 code:

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

what 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 to use sys.exc_clear(), but this method is removed from python 3 too. I can use workaround that works

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

but I believe that there is better solution.

like image 768
Rugnar Avatar asked Nov 19 '15 16:11

Rugnar


People also ask

What are chained exceptions in Python?

An implicit form of chained exceptions occurs when another exception gets raised inside an except block. In the code below, the NameError exception is raised as the result of a programming error, not in direct response to the parsing error.

What is Python OSError?

OSError is a built-in exception in Python and serves as the error class for the os module, which is raised when an os specific system function returns a system-related error, including I/O failures such as “file not found” or “disk full”.

What is BaseException in Python?

The BaseException is the base class of all other exceptions. User defined classes cannot be directly derived from this class, to derive user defied class, we need to use Exception class. The Python Exception Hierarchy is like below. BaseException.

How do you propagate exceptions in Python?

When an exception is raised, the exception-propagation mechanism takes control. The normal control flow of the program stops, and Python looks for a suitable exception handler. Python's try statement establishes exception handlers via its except clauses.


1 Answers

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 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 
like image 114
Trey Hunner Avatar answered Sep 20 '22 13:09

Trey Hunner