In the module warnings (https://docs.python.org/3.5/library/warnings.html) there is the ability to raise a warning that appears to come from somewhere earlier in the stack:<
If I understand correctly, you would like the output of this minimal example:
def check_raise(function):
try:
return function()
except Exception:
raise RuntimeError('An exception was raised.')
def function():
1/0
check_raise(function)
to be only this:
Traceback (most recent call last):
File "tb2.py", line 10, in
check_raise(function)
RuntimeError: An exception was raised.
In fact, it's a lot more output; there is exception chaining, which could be dealt with by handling the RuntimeError
immediately, removing its __context__
, and re-raising it, and there is another line of traceback for the RuntimeError
itself:
File "tb2.py", line 5, in check_raise
raise RuntimeError('An exception was raised.')
As far as I can tell, it is not possible for pure Python code to substitute the traceback of an exception after it was raised; the interpreter has control of adding to it but it only exposes the current traceback whenever the exception is handled. There is no API (not even when using tracing functions) for passing your own traceback to the interpreter, and traceback objects are immutable (this is what's tackled by that Jinja hack involving C-level stuff).
So further assuming that you're interested in the shortened traceback not for further programmatic use but only for user-friendly output, your best bet will be an excepthook
that controls how the traceback is printed to the console. For determining where to stop printing, a special local variable could be used (this is a bit more robust than limiting the traceback to its length minus 1 or such). This example requires Python 3.5 (for traceback.walk_tb
):
import sys
import traceback
def check_raise(function):
__exclude_from_traceback_from_here__ = True
try:
return function()
except Exception:
raise RuntimeError('An exception was raised.')
def print_traceback(exc_type, exc_value, tb):
for i, (frame, lineno) in enumerate(traceback.walk_tb(tb)):
if '__exclude_from_traceback_from_here__' in frame.f_code.co_varnames:
limit = i
break
else:
limit = None
traceback.print_exception(
exc_type, exc_value, tb, limit=limit, chain=False)
sys.excepthook = print_traceback
def function():
1/0
check_raise(function)
This is the output now:
Traceback (most recent call last):
File "tb2.py", line 26, in
check_raise(function)
RuntimeError: An exception was raised.