exceptions.py 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. from __future__ import absolute_import
  2. import inspect
  3. import traceback
  4. import bb.namedtuple_with_abc
  5. from collections import namedtuple
  6. class TracebackEntry(namedtuple.abc):
  7. """Pickleable representation of a traceback entry"""
  8. _fields = 'filename lineno function args code_context index'
  9. _header = ' File "{0.filename}", line {0.lineno}, in {0.function}{0.args}'
  10. def format(self, formatter=None):
  11. if not self.code_context:
  12. return self._header.format(self) + '\n'
  13. formatted = [self._header.format(self) + ':\n']
  14. for lineindex, line in enumerate(self.code_context):
  15. if formatter:
  16. line = formatter(line)
  17. if lineindex == self.index:
  18. formatted.append(' >%s' % line)
  19. else:
  20. formatted.append(' %s' % line)
  21. return formatted
  22. def __str__(self):
  23. return ''.join(self.format())
  24. def _get_frame_args(frame):
  25. """Get the formatted arguments and class (if available) for a frame"""
  26. arginfo = inspect.getargvalues(frame)
  27. try:
  28. if not arginfo.args:
  29. return '', None
  30. # There have been reports from the field of python 2.6 which doesn't
  31. # return a namedtuple here but simply a tuple so fallback gracefully if
  32. # args isn't present.
  33. except AttributeError:
  34. return '', None
  35. firstarg = arginfo.args[0]
  36. if firstarg == 'self':
  37. self = arginfo.locals['self']
  38. cls = self.__class__.__name__
  39. arginfo.args.pop(0)
  40. del arginfo.locals['self']
  41. else:
  42. cls = None
  43. formatted = inspect.formatargvalues(*arginfo)
  44. return formatted, cls
  45. def extract_traceback(tb, context=1):
  46. frames = inspect.getinnerframes(tb, context)
  47. for frame, filename, lineno, function, code_context, index in frames:
  48. formatted_args, cls = _get_frame_args(frame)
  49. if cls:
  50. function = '%s.%s' % (cls, function)
  51. yield TracebackEntry(filename, lineno, function, formatted_args,
  52. code_context, index)
  53. def format_extracted(extracted, formatter=None, limit=None):
  54. if limit:
  55. extracted = extracted[-limit:]
  56. formatted = []
  57. for tracebackinfo in extracted:
  58. formatted.extend(tracebackinfo.format(formatter))
  59. return formatted
  60. def format_exception(etype, value, tb, context=1, limit=None, formatter=None):
  61. formatted = ['Traceback (most recent call last):\n']
  62. if hasattr(tb, 'tb_next'):
  63. tb = extract_traceback(tb, context)
  64. formatted.extend(format_extracted(tb, formatter, limit))
  65. formatted.extend(traceback.format_exception_only(etype, value))
  66. return formatted
  67. def to_string(exc):
  68. if isinstance(exc, SystemExit):
  69. if not isinstance(exc.code, basestring):
  70. return 'Exited with "%d"' % exc.code
  71. return str(exc)