use tb_offset to correctly format stack trace

This commit is contained in:
Nathan Page 2021-02-07 19:40:27 -08:00
parent 22d55908d2
commit 1d08a76c2e
1 changed files with 38 additions and 13 deletions

View File

@ -88,27 +88,52 @@ def install(
) )
) )
try: # pragma: no cover def ipy_excepthook_closure(ip) -> None:
ip = get_ipython() # type: ignore tb_data = {} # store information about showtraceback call
default_showtraceback = ip.showtraceback # keep reference of default traceback
def ipy_excepthook(is_syntax: bool = False) -> None: def ipy_show_traceback(*args, **kwargs) -> None:
"""wrap the default ip.showtraceback to store info for ip._showtraceback"""
nonlocal tb_data
tb_data = kwargs
default_showtraceback(*args, **kwargs)
def ipy_display_traceback(*args, is_syntax: bool = False, **kwargs) -> None:
"""Internally called traceback from ip._showtraceback"""
nonlocal tb_data
exc_tuple = ip._get_exc_info() exc_tuple = ip._get_exc_info()
# syntax errors will show no traceback # do not display trace on syntax error
if is_syntax: tb: Optional[TracebackType] = None if is_syntax else exc_tuple[2]
exc_tuple = exc_tuple[0], exc_tuple[1], None
else: # determine correct tb_offset
# remove traceback of ipython exec call compiled = tb_data.get("running_compiled_code", False)
exc_tuple = exc_tuple[0], exc_tuple[1], exc_tuple[2].tb_next tb_offset = tb_data.get("tb_offset", 1 if compiled else 0)
excepthook(*exc_tuple) # type: ignore # remove ipython internal frames from trace with tb_offset
for _ in range(tb_offset):
if tb is None:
break
tb = tb.tb_next
excepthook(exc_tuple[0], exc_tuple[1], tb)
tb_data = {} # clear data upon usage
# replace _showtraceback instead of showtraceback to allow ipython features such as debugging to work # replace _showtraceback instead of showtraceback to allow ipython features such as debugging to work
# this is also what the ipython docs recommends to modify when subcalssing InteractiveShell # this is also what the ipython docs recommends to modify when subclassing InteractiveShell
ip._showtraceback = lambda *args, **kwargs: ipy_excepthook() ip._showtraceback = ipy_display_traceback
ip.showsyntaxerror = lambda *args, **kwargs: ipy_excepthook(is_syntax=True) # add wrapper to capture tb_data
ip.showtraceback = ipy_show_traceback
ip.showsyntaxerror = lambda *args, **kwargs: ipy_display_traceback(
*args, is_syntax=True, **kwargs
)
try: # pragma: no cover
# if wihin ipython, use customized traceback
ip = get_ipython() # type: ignore
ipy_excepthook_closure(ip)
return sys.excepthook return sys.excepthook
except Exception: except Exception:
# otherwise use default system hook
old_excepthook = sys.excepthook old_excepthook = sys.excepthook
sys.excepthook = excepthook sys.excepthook = excepthook
return old_excepthook return old_excepthook