Reputation: 2270
In Python 2.7, the following will only print one traceback, from the exception raised in the except
block:
try:
1/0
except ZeroDivisionError:
raise Exception("Error!")
Output:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
Exception: Error!
However in Python 3 there is exception chaining. Here is the output for the same code:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
Exception: Error!
I need to write some code that is compatible with both Python 2.7 and Python 3, and I need for there to be no exception chaining when the exception is raised inside that except
block. So that the output will be what you see above when that code is executed in Python 2.7.
The one possible solution I've found is raise_from
, included in the six
module:
from six import raise_from
try:
1/0
except ZeroDivisionError:
raise_from(Exception("Error!"), None)
However, it adds an extra line for raise_from
to the traceback that I'd like to avoid:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
File "<string>", line 3, in raise_from
Exception: Error!
Is there any way to do this?
Upvotes: 2
Views: 233
Reputation: 5871
The following produces identical output on py2.7.13 and py3.9.2, if you call it with the full path. (If you use a relative path, py3 expands it, but py2 does not.)
try:
1/0
except ZeroDivisionError:
internal = Exception("Error!")
internal.__suppress_context__ = True
raise internal
Traceback (most recent call last):
File "b:\development\python\so.py", line 6, in
raise internal
Exception: Error!
I was hoping to avoid internal attributes that might change, but __suppress_context__ is documented https://docs.python.org/3/library/exceptions.html
Upvotes: 3
Reputation: 50076
Use a finally
block to discard the context after the exception was raised:
try:
1/0
except ZeroDivisionError:
# store exception to allow modifying it
exc = Exception("Error!")
try:
raise exc
finally:
# context has been set here already – discard it
exc.__context__ = None
This also works in Python2 for any proper exception, i.e. those derived from BaseException
.
Upvotes: 1