Reputation: 2845
I have a common situation in my projects, where I use custom Exceptions to wrap built in exception scenarios, like:
# meaningless here but in other situations its useful...
try:
5/0
except ZeroDivisionError as e:
raise MyCustomException(msg=str(e))
along with a universal exception handler that looks like this:
@app.errorhandler(Exception) # this decorator is flask related - ignore it
def handle_error(error):
if isinstance(error, MyCustomException):
# some code
# I only want MyCustomException traceback
else:
# some other code
exc_stack = traceback.format_exc(limit=5)
The known issue here is that I get both exception tracebacks, whereas in if-case I want only the last one.
There are two solutions in this problem as far as I know.
First workaround (use from None
):
try:
5/0
except ZeroDivisionError as e:
raise MyCustomException(msg=str(e)) from None # python3
Second workaround (call the traceback before raising the second exception)
try:
5/0
except ZeroDivisionError as e:
tracb = traceback.format_exc(limit=5)
raise MyCustomException(msg=str(e), tracb_msg=tracb)
No need to call traceback.format_exc()
in exception handler, just use the tracb_msg
passed to the instance. Obviously first workaround is simpler.
My Problem:
Both of these approaches re-appear (repeating code/trick) dozens of times inside the code, every time I raise MyCustomException
. Has anyone come up with a trick to handle this once inside the handler function?
Upvotes: 3
Views: 1838
Reputation: 56620
Use the __suppress_context__
attribute to disable context printing.
According to the docs, using raise MyCustomException(foo) from bar
sets __cause__
to bar
, and __context__
to the original exception (the implicitly chained exception).
An implicitly chained exception in
__context__
is shown only if__cause__
is None and__suppress_context__
is false.
Here's an example:
# Declare an exception that never shows context.
class MyCustomException(Exception):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__suppress_context__ = True
try:
1/0
except ZeroDivisionError as e:
raise MyCustomException(str(e))
Here's the output I get:
Traceback (most recent call last):
File "/home/don/workspace/scratch/scratch.py", line 12, in <module>
raise MyCustomException(str(e))
MyCustomException: division by zero
Here's the output if I set __suppress_context__
to False
:
Traceback (most recent call last):
File "/home/don/workspace/scratch/scratch.py", line 10, in <module>
1/0
ZeroDivisionError: division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/don/workspace/scratch/scratch.py", line 12, in <module>
raise MyCustomException(str(e))
MyCustomException: division by zero
Upvotes: 3