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