einfo.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. from __future__ import absolute_import
  2. import sys
  3. import traceback
  4. __all__ = ['ExceptionInfo', 'Traceback']
  5. DEFAULT_MAX_FRAMES = sys.getrecursionlimit() // 8
  6. class _Code(object):
  7. def __init__(self, code):
  8. self.co_filename = code.co_filename
  9. self.co_name = code.co_name
  10. self.co_argcount = code.co_argcount
  11. self.co_cellvars = ()
  12. self.co_firstlineno = code.co_firstlineno
  13. self.co_flags = code.co_flags
  14. self.co_freevars = ()
  15. self.co_code = b''
  16. self.co_lnotab = b''
  17. self.co_names = code.co_names
  18. self.co_nlocals = code.co_nlocals
  19. self.co_stacksize = code.co_stacksize
  20. self.co_varnames = ()
  21. class _Frame(object):
  22. Code = _Code
  23. def __init__(self, frame):
  24. self.f_builtins = {}
  25. self.f_globals = {
  26. "__file__": frame.f_globals.get("__file__", "__main__"),
  27. "__name__": frame.f_globals.get("__name__"),
  28. "__loader__": None,
  29. }
  30. self.f_locals = fl = {}
  31. try:
  32. fl["__traceback_hide__"] = frame.f_locals["__traceback_hide__"]
  33. except KeyError:
  34. pass
  35. self.f_back = None
  36. self.f_trace = None
  37. self.f_exc_traceback = None
  38. self.f_exc_type = None
  39. self.f_exc_value = None
  40. self.f_code = self.Code(frame.f_code)
  41. self.f_lineno = frame.f_lineno
  42. self.f_lasti = frame.f_lasti
  43. # don't want to hit https://bugs.python.org/issue21967
  44. self.f_restricted = False
  45. class _Object(object):
  46. def __init__(self, **kw):
  47. [setattr(self, k, v) for k, v in kw.items()]
  48. class _Truncated(object):
  49. def __init__(self):
  50. self.tb_lineno = -1
  51. self.tb_frame = _Object(
  52. f_globals={"__file__": "",
  53. "__name__": "",
  54. "__loader__": None},
  55. f_fileno=None,
  56. f_code=_Object(co_filename="...",
  57. co_name="[rest of traceback truncated]"),
  58. )
  59. self.tb_next = None
  60. self.tb_lasti = 0
  61. class Traceback(object):
  62. Frame = _Frame
  63. def __init__(self, tb, max_frames=DEFAULT_MAX_FRAMES, depth=0):
  64. self.tb_frame = self.Frame(tb.tb_frame)
  65. self.tb_lineno = tb.tb_lineno
  66. self.tb_lasti = tb.tb_lasti
  67. self.tb_next = None
  68. if tb.tb_next is not None:
  69. if depth <= max_frames:
  70. self.tb_next = Traceback(tb.tb_next, max_frames, depth + 1)
  71. else:
  72. self.tb_next = _Truncated()
  73. class ExceptionInfo(object):
  74. """Exception wrapping an exception and its traceback.
  75. :param exc_info: The exception info tuple as returned by
  76. :func:`sys.exc_info`.
  77. """
  78. #: Exception type.
  79. type = None
  80. #: Exception instance.
  81. exception = None
  82. #: Pickleable traceback instance for use with :mod:`traceback`
  83. tb = None
  84. #: String representation of the traceback.
  85. traceback = None
  86. #: Set to true if this is an internal error.
  87. internal = False
  88. def __init__(self, exc_info=None, internal=False):
  89. self.type, self.exception, tb = exc_info or sys.exc_info()
  90. try:
  91. self.tb = Traceback(tb)
  92. self.traceback = ''.join(
  93. traceback.format_exception(self.type, self.exception, tb),
  94. )
  95. self.internal = internal
  96. finally:
  97. del(tb)
  98. def __str__(self):
  99. return self.traceback
  100. def __repr__(self):
  101. return "<%s: %r>" % (self.__class__.__name__, self.exception, )
  102. @property
  103. def exc_info(self):
  104. return self.type, self.exception, self.tb