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