diff options
Diffstat (limited to 'lib/bb/exceptions.py')
-rw-r--r-- | lib/bb/exceptions.py | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/lib/bb/exceptions.py b/lib/bb/exceptions.py new file mode 100644 index 0000000000..13269de8c1 --- /dev/null +++ b/lib/bb/exceptions.py @@ -0,0 +1,55 @@ +from __future__ import absolute_import +import inspect +import traceback +import bb.namedtuple_with_abc +from collections import namedtuple + + +class TracebackEntry(namedtuple.abc): + """Pickleable representation of a traceback entry""" + _fields = 'filename lineno function args code_context index' + _header = ' File "{0.filename}", line {0.lineno}, in {0.function}{0.args}:\n' + + def format(self, formatter=None): + formatted = [self._header.format(self)] + + for lineindex, line in enumerate(self.code_context): + if formatter: + line = formatter(line) + + if lineindex == self.index: + formatted.append(' >%s' % line) + else: + formatted.append(' %s' % line) + return formatted + + def __str__(self): + return ''.join(self.format()) + + +def extract_traceback(tb, context=1): + frames = inspect.getinnerframes(tb, context) + for frame, filename, lineno, function, code_context, index in frames: + args = inspect.formatargvalues(*inspect.getargvalues(frame)) + yield TracebackEntry(filename, lineno, function, args, code_context, index) + + +def format_extracted(extracted, formatter=None, limit=None): + if limit: + extracted = extracted[-limit:] + + formatted = [] + for tracebackinfo in extracted: + formatted.extend(tracebackinfo.format(formatter)) + return formatted + + +def format_exception(etype, value, tb, context=1, limit=None, formatter=None): + formatted = ['Traceback (most recent call last):\n'] + + if hasattr(tb, 'tb_next'): + tb = extract_traceback(tb, context) + + formatted.extend(format_extracted(tb, formatter, limit)) + formatted.extend(traceback.format_exception_only(etype, value)) + return formatted |