Reputation: 43
I'm trying to raise an exception with a stacktrace that doesn't include the last Frame.
In python 2 it was possible to remove the last entry from the strack like this:
def exceptionCatcher(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception:
excInfo = sys.exc_info()
# some custom logging stuff
raise excInfo[0], excInfo[1], excInfo[2].tb_next
return wrapper
def a():
raise Exception("My Exception")
@exceptionCatcher
def test():
a()
This worked in python and excluded the last exceptionCatcher call itself from the traceback e.g.
Traceback (most recent call last):
File "test.py", line 15, in <module>
test()
File "test.py", line 12, in a
raise Exception("a")
Exception: a
instead of
Traceback (most recent call last):
File "test.py", line 12, in <module>
test()
File "test.py", line 9, in wrapper
raise e
File "test.py", line 5, in wrapper
return func(*args, **kwargs)
File "test.py", line 10, in test
a()
File "test.py", line 5, in a
raise Exception("a")
Exception: a
Switching to python3 it's not possible to raise an exception like:
raise excInfo[0], excInfo[1], excInfo[2].tb_next
and i had to use:
def exceptionCatcher(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
excInfo = sys.exc_info()
# some custom logging stuff
raise e.with_traceback(excInfo[2].tb_next)
...
Which added the following line to my traceback:
Traceback (most recent call last):
File "test.py", line 12, in <module>
test()
File "test.py", line 9, in wrapper
raise e.with_traceback(excInfo[2].tb_next)
File "test.py", line 10, in test
a()
File "test.py", line 5, in a
raise Exception("a")
Exception: a
Is there any way to get rid of this part of the traceback?
I know exceptionCatching can be done with the exceptionhook but in the scenario i'm using this it's not possible to use the exceptionhook as it's another third party application (in cpp) which seems to catch the exception so the exceptionhook won't catch any. So i came up with the idea of using a wrapper decorator as shown above eventho it's a hacky way.
Upvotes: 1
Views: 75
Reputation: 531085
Instead of a decorator, use a context manager, which doesn't add a stack frame in the first place.
import contextlib
@contextlib.contextmanager
def exceptionCatcher():
try:
yield
except Exception as e:
print("custom logging")
raise
def a():
raise Exception("My Exception")
def test():
with exceptionCatcher():
a()
test()
Upvotes: 1