diff --git a/visidata/errors.py b/visidata/errors.py index a96cc16a2..af48d2167 100644 --- a/visidata/errors.py +++ b/visidata/errors.py @@ -1,4 +1,5 @@ import traceback +import re from visidata import vd, VisiData @@ -11,8 +12,23 @@ class ExpectedException(Exception): def stacktrace(e=None): + '''Return a list of strings. Includes extra callstack levels above the + level where the exception was technically caught, to aid debugging.''' + if not e: - return traceback.format_exc().strip().splitlines() + stack = ''.join(traceback.format_stack()).strip().splitlines() + trim_levels = 3 # calling function -> stacktrace() -> format_stack() + trace_above = stack[:-2*trim_levels] + trace_above[0] = ' ' + trace_above[0] #fix indent level of first line + try: + # remove several levels of uninformative stacktrace in typical interactive vd + idx = trace_above.index(' ret = vd.mainloop(scr)') + trace_above = trace_above[idx+1:] + except ValueError: + pass + # remove lines that mark error columns with carets and sometimes tildes + trace_below = [ line for line in traceback.format_exc().strip().splitlines() if not re.match('^ *~*\\^+$', line) ] + return [trace_below[0]] + trace_above + trace_below[1:] return traceback.format_exception_only(type(e), e)