from __future__ import absolute_import import sys import traceback __all__ = ['ExceptionInfo', 'Traceback'] DEFAULT_MAX_FRAMES = sys.getrecursionlimit() // 8 class _Code(object): def __init__(self, code): self.co_filename = code.co_filename self.co_name = code.co_name self.co_argcount = code.co_argcount self.co_cellvars = () self.co_firstlineno = code.co_firstlineno self.co_flags = code.co_flags self.co_freevars = () self.co_code = b'' self.co_lnotab = b'' self.co_names = code.co_names self.co_nlocals = code.co_nlocals self.co_stacksize = code.co_stacksize self.co_varnames = () class _Frame(object): Code = _Code def __init__(self, frame): self.f_builtins = {} self.f_globals = { "__file__": frame.f_globals.get("__file__", "__main__"), "__name__": frame.f_globals.get("__name__"), "__loader__": None, } self.f_locals = fl = {} try: fl["__traceback_hide__"] = frame.f_locals["__traceback_hide__"] except KeyError: pass self.f_trace = None self.f_exc_traceback = None self.f_exc_type = None self.f_exc_value = None self.f_code = self.Code(frame.f_code) self.f_lineno = frame.f_lineno self.f_lasti = frame.f_lasti # don't want to hit https://bugs.python.org/issue21967 self.f_restricted = False class _Object(object): def __init__(self, **kw): [setattr(self, k, v) for k, v in kw.items()] class _Truncated(object): def __init__(self): self.tb_lineno = -1 self.tb_frame = _Object( f_globals={"__file__": "", "__name__": "", "__loader__": None}, f_fileno=None, f_code=_Object(co_filename="...", co_name="[rest of traceback truncated]"), ) self.tb_next = None self.tb_lasti = 0 class Traceback(object): Frame = _Frame def __init__(self, tb, max_frames=DEFAULT_MAX_FRAMES, depth=0): self.tb_frame = self.Frame(tb.tb_frame) self.tb_lineno = tb.tb_lineno self.tb_lasti = tb.tb_lasti self.tb_next = None if tb.tb_next is not None: if depth <= max_frames: self.tb_next = Traceback(tb.tb_next, max_frames, depth + 1) else: self.tb_next = _Truncated() class ExceptionInfo(object): """Exception wrapping an exception and its traceback. :param exc_info: The exception info tuple as returned by :func:`sys.exc_info`. """ #: Exception type. type = None #: Exception instance. exception = None #: Pickleable traceback instance for use with :mod:`traceback` tb = None #: String representation of the traceback. traceback = None #: Set to true if this is an internal error. internal = False def __init__(self, exc_info=None, internal=False): self.type, self.exception, tb = exc_info or sys.exc_info() try: self.tb = Traceback(tb) self.traceback = ''.join( traceback.format_exception(self.type, self.exception, tb), ) self.internal = internal finally: del(tb) def __str__(self): return self.traceback def __repr__(self): return "" % (self.exception, ) @property def exc_info(self): return self.type, self.exception, self.tb