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) | ||