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