1*cda5da8dSAndroid Build Coastguard Worker"""Extract, format and print information about Python stack traces.""" 2*cda5da8dSAndroid Build Coastguard Worker 3*cda5da8dSAndroid Build Coastguard Workerimport collections.abc 4*cda5da8dSAndroid Build Coastguard Workerimport itertools 5*cda5da8dSAndroid Build Coastguard Workerimport linecache 6*cda5da8dSAndroid Build Coastguard Workerimport sys 7*cda5da8dSAndroid Build Coastguard Workerimport textwrap 8*cda5da8dSAndroid Build Coastguard Workerfrom contextlib import suppress 9*cda5da8dSAndroid Build Coastguard Worker 10*cda5da8dSAndroid Build Coastguard Worker__all__ = ['extract_stack', 'extract_tb', 'format_exception', 11*cda5da8dSAndroid Build Coastguard Worker 'format_exception_only', 'format_list', 'format_stack', 12*cda5da8dSAndroid Build Coastguard Worker 'format_tb', 'print_exc', 'format_exc', 'print_exception', 13*cda5da8dSAndroid Build Coastguard Worker 'print_last', 'print_stack', 'print_tb', 'clear_frames', 14*cda5da8dSAndroid Build Coastguard Worker 'FrameSummary', 'StackSummary', 'TracebackException', 15*cda5da8dSAndroid Build Coastguard Worker 'walk_stack', 'walk_tb'] 16*cda5da8dSAndroid Build Coastguard Worker 17*cda5da8dSAndroid Build Coastguard Worker# 18*cda5da8dSAndroid Build Coastguard Worker# Formatting and printing lists of traceback lines. 19*cda5da8dSAndroid Build Coastguard Worker# 20*cda5da8dSAndroid Build Coastguard Worker 21*cda5da8dSAndroid Build Coastguard Workerdef print_list(extracted_list, file=None): 22*cda5da8dSAndroid Build Coastguard Worker """Print the list of tuples as returned by extract_tb() or 23*cda5da8dSAndroid Build Coastguard Worker extract_stack() as a formatted stack trace to the given file.""" 24*cda5da8dSAndroid Build Coastguard Worker if file is None: 25*cda5da8dSAndroid Build Coastguard Worker file = sys.stderr 26*cda5da8dSAndroid Build Coastguard Worker for item in StackSummary.from_list(extracted_list).format(): 27*cda5da8dSAndroid Build Coastguard Worker print(item, file=file, end="") 28*cda5da8dSAndroid Build Coastguard Worker 29*cda5da8dSAndroid Build Coastguard Workerdef format_list(extracted_list): 30*cda5da8dSAndroid Build Coastguard Worker """Format a list of tuples or FrameSummary objects for printing. 31*cda5da8dSAndroid Build Coastguard Worker 32*cda5da8dSAndroid Build Coastguard Worker Given a list of tuples or FrameSummary objects as returned by 33*cda5da8dSAndroid Build Coastguard Worker extract_tb() or extract_stack(), return a list of strings ready 34*cda5da8dSAndroid Build Coastguard Worker for printing. 35*cda5da8dSAndroid Build Coastguard Worker 36*cda5da8dSAndroid Build Coastguard Worker Each string in the resulting list corresponds to the item with the 37*cda5da8dSAndroid Build Coastguard Worker same index in the argument list. Each string ends in a newline; 38*cda5da8dSAndroid Build Coastguard Worker the strings may contain internal newlines as well, for those items 39*cda5da8dSAndroid Build Coastguard Worker whose source text line is not None. 40*cda5da8dSAndroid Build Coastguard Worker """ 41*cda5da8dSAndroid Build Coastguard Worker return StackSummary.from_list(extracted_list).format() 42*cda5da8dSAndroid Build Coastguard Worker 43*cda5da8dSAndroid Build Coastguard Worker# 44*cda5da8dSAndroid Build Coastguard Worker# Printing and Extracting Tracebacks. 45*cda5da8dSAndroid Build Coastguard Worker# 46*cda5da8dSAndroid Build Coastguard Worker 47*cda5da8dSAndroid Build Coastguard Workerdef print_tb(tb, limit=None, file=None): 48*cda5da8dSAndroid Build Coastguard Worker """Print up to 'limit' stack trace entries from the traceback 'tb'. 49*cda5da8dSAndroid Build Coastguard Worker 50*cda5da8dSAndroid Build Coastguard Worker If 'limit' is omitted or None, all entries are printed. If 'file' 51*cda5da8dSAndroid Build Coastguard Worker is omitted or None, the output goes to sys.stderr; otherwise 52*cda5da8dSAndroid Build Coastguard Worker 'file' should be an open file or file-like object with a write() 53*cda5da8dSAndroid Build Coastguard Worker method. 54*cda5da8dSAndroid Build Coastguard Worker """ 55*cda5da8dSAndroid Build Coastguard Worker print_list(extract_tb(tb, limit=limit), file=file) 56*cda5da8dSAndroid Build Coastguard Worker 57*cda5da8dSAndroid Build Coastguard Workerdef format_tb(tb, limit=None): 58*cda5da8dSAndroid Build Coastguard Worker """A shorthand for 'format_list(extract_tb(tb, limit))'.""" 59*cda5da8dSAndroid Build Coastguard Worker return extract_tb(tb, limit=limit).format() 60*cda5da8dSAndroid Build Coastguard Worker 61*cda5da8dSAndroid Build Coastguard Workerdef extract_tb(tb, limit=None): 62*cda5da8dSAndroid Build Coastguard Worker """ 63*cda5da8dSAndroid Build Coastguard Worker Return a StackSummary object representing a list of 64*cda5da8dSAndroid Build Coastguard Worker pre-processed entries from traceback. 65*cda5da8dSAndroid Build Coastguard Worker 66*cda5da8dSAndroid Build Coastguard Worker This is useful for alternate formatting of stack traces. If 67*cda5da8dSAndroid Build Coastguard Worker 'limit' is omitted or None, all entries are extracted. A 68*cda5da8dSAndroid Build Coastguard Worker pre-processed stack trace entry is a FrameSummary object 69*cda5da8dSAndroid Build Coastguard Worker containing attributes filename, lineno, name, and line 70*cda5da8dSAndroid Build Coastguard Worker representing the information that is usually printed for a stack 71*cda5da8dSAndroid Build Coastguard Worker trace. The line is a string with leading and trailing 72*cda5da8dSAndroid Build Coastguard Worker whitespace stripped; if the source is not available it is None. 73*cda5da8dSAndroid Build Coastguard Worker """ 74*cda5da8dSAndroid Build Coastguard Worker return StackSummary._extract_from_extended_frame_gen( 75*cda5da8dSAndroid Build Coastguard Worker _walk_tb_with_full_positions(tb), limit=limit) 76*cda5da8dSAndroid Build Coastguard Worker 77*cda5da8dSAndroid Build Coastguard Worker# 78*cda5da8dSAndroid Build Coastguard Worker# Exception formatting and output. 79*cda5da8dSAndroid Build Coastguard Worker# 80*cda5da8dSAndroid Build Coastguard Worker 81*cda5da8dSAndroid Build Coastguard Worker_cause_message = ( 82*cda5da8dSAndroid Build Coastguard Worker "\nThe above exception was the direct cause " 83*cda5da8dSAndroid Build Coastguard Worker "of the following exception:\n\n") 84*cda5da8dSAndroid Build Coastguard Worker 85*cda5da8dSAndroid Build Coastguard Worker_context_message = ( 86*cda5da8dSAndroid Build Coastguard Worker "\nDuring handling of the above exception, " 87*cda5da8dSAndroid Build Coastguard Worker "another exception occurred:\n\n") 88*cda5da8dSAndroid Build Coastguard Worker 89*cda5da8dSAndroid Build Coastguard Worker 90*cda5da8dSAndroid Build Coastguard Workerclass _Sentinel: 91*cda5da8dSAndroid Build Coastguard Worker def __repr__(self): 92*cda5da8dSAndroid Build Coastguard Worker return "<implicit>" 93*cda5da8dSAndroid Build Coastguard Worker 94*cda5da8dSAndroid Build Coastguard Worker_sentinel = _Sentinel() 95*cda5da8dSAndroid Build Coastguard Worker 96*cda5da8dSAndroid Build Coastguard Workerdef _parse_value_tb(exc, value, tb): 97*cda5da8dSAndroid Build Coastguard Worker if (value is _sentinel) != (tb is _sentinel): 98*cda5da8dSAndroid Build Coastguard Worker raise ValueError("Both or neither of value and tb must be given") 99*cda5da8dSAndroid Build Coastguard Worker if value is tb is _sentinel: 100*cda5da8dSAndroid Build Coastguard Worker if exc is not None: 101*cda5da8dSAndroid Build Coastguard Worker if isinstance(exc, BaseException): 102*cda5da8dSAndroid Build Coastguard Worker return exc, exc.__traceback__ 103*cda5da8dSAndroid Build Coastguard Worker 104*cda5da8dSAndroid Build Coastguard Worker raise TypeError(f'Exception expected for value, ' 105*cda5da8dSAndroid Build Coastguard Worker f'{type(exc).__name__} found') 106*cda5da8dSAndroid Build Coastguard Worker else: 107*cda5da8dSAndroid Build Coastguard Worker return None, None 108*cda5da8dSAndroid Build Coastguard Worker return value, tb 109*cda5da8dSAndroid Build Coastguard Worker 110*cda5da8dSAndroid Build Coastguard Worker 111*cda5da8dSAndroid Build Coastguard Workerdef print_exception(exc, /, value=_sentinel, tb=_sentinel, limit=None, \ 112*cda5da8dSAndroid Build Coastguard Worker file=None, chain=True): 113*cda5da8dSAndroid Build Coastguard Worker """Print exception up to 'limit' stack trace entries from 'tb' to 'file'. 114*cda5da8dSAndroid Build Coastguard Worker 115*cda5da8dSAndroid Build Coastguard Worker This differs from print_tb() in the following ways: (1) if 116*cda5da8dSAndroid Build Coastguard Worker traceback is not None, it prints a header "Traceback (most recent 117*cda5da8dSAndroid Build Coastguard Worker call last):"; (2) it prints the exception type and value after the 118*cda5da8dSAndroid Build Coastguard Worker stack trace; (3) if type is SyntaxError and value has the 119*cda5da8dSAndroid Build Coastguard Worker appropriate format, it prints the line where the syntax error 120*cda5da8dSAndroid Build Coastguard Worker occurred with a caret on the next line indicating the approximate 121*cda5da8dSAndroid Build Coastguard Worker position of the error. 122*cda5da8dSAndroid Build Coastguard Worker """ 123*cda5da8dSAndroid Build Coastguard Worker value, tb = _parse_value_tb(exc, value, tb) 124*cda5da8dSAndroid Build Coastguard Worker te = TracebackException(type(value), value, tb, limit=limit, compact=True) 125*cda5da8dSAndroid Build Coastguard Worker te.print(file=file, chain=chain) 126*cda5da8dSAndroid Build Coastguard Worker 127*cda5da8dSAndroid Build Coastguard Worker 128*cda5da8dSAndroid Build Coastguard Workerdef format_exception(exc, /, value=_sentinel, tb=_sentinel, limit=None, \ 129*cda5da8dSAndroid Build Coastguard Worker chain=True): 130*cda5da8dSAndroid Build Coastguard Worker """Format a stack trace and the exception information. 131*cda5da8dSAndroid Build Coastguard Worker 132*cda5da8dSAndroid Build Coastguard Worker The arguments have the same meaning as the corresponding arguments 133*cda5da8dSAndroid Build Coastguard Worker to print_exception(). The return value is a list of strings, each 134*cda5da8dSAndroid Build Coastguard Worker ending in a newline and some containing internal newlines. When 135*cda5da8dSAndroid Build Coastguard Worker these lines are concatenated and printed, exactly the same text is 136*cda5da8dSAndroid Build Coastguard Worker printed as does print_exception(). 137*cda5da8dSAndroid Build Coastguard Worker """ 138*cda5da8dSAndroid Build Coastguard Worker value, tb = _parse_value_tb(exc, value, tb) 139*cda5da8dSAndroid Build Coastguard Worker te = TracebackException(type(value), value, tb, limit=limit, compact=True) 140*cda5da8dSAndroid Build Coastguard Worker return list(te.format(chain=chain)) 141*cda5da8dSAndroid Build Coastguard Worker 142*cda5da8dSAndroid Build Coastguard Worker 143*cda5da8dSAndroid Build Coastguard Workerdef format_exception_only(exc, /, value=_sentinel): 144*cda5da8dSAndroid Build Coastguard Worker """Format the exception part of a traceback. 145*cda5da8dSAndroid Build Coastguard Worker 146*cda5da8dSAndroid Build Coastguard Worker The return value is a list of strings, each ending in a newline. 147*cda5da8dSAndroid Build Coastguard Worker 148*cda5da8dSAndroid Build Coastguard Worker Normally, the list contains a single string; however, for 149*cda5da8dSAndroid Build Coastguard Worker SyntaxError exceptions, it contains several lines that (when 150*cda5da8dSAndroid Build Coastguard Worker printed) display detailed information about where the syntax 151*cda5da8dSAndroid Build Coastguard Worker error occurred. 152*cda5da8dSAndroid Build Coastguard Worker 153*cda5da8dSAndroid Build Coastguard Worker The message indicating which exception occurred is always the last 154*cda5da8dSAndroid Build Coastguard Worker string in the list. 155*cda5da8dSAndroid Build Coastguard Worker 156*cda5da8dSAndroid Build Coastguard Worker """ 157*cda5da8dSAndroid Build Coastguard Worker if value is _sentinel: 158*cda5da8dSAndroid Build Coastguard Worker value = exc 159*cda5da8dSAndroid Build Coastguard Worker te = TracebackException(type(value), value, None, compact=True) 160*cda5da8dSAndroid Build Coastguard Worker return list(te.format_exception_only()) 161*cda5da8dSAndroid Build Coastguard Worker 162*cda5da8dSAndroid Build Coastguard Worker 163*cda5da8dSAndroid Build Coastguard Worker# -- not official API but folk probably use these two functions. 164*cda5da8dSAndroid Build Coastguard Worker 165*cda5da8dSAndroid Build Coastguard Workerdef _format_final_exc_line(etype, value): 166*cda5da8dSAndroid Build Coastguard Worker valuestr = _safe_string(value, 'exception') 167*cda5da8dSAndroid Build Coastguard Worker if value is None or not valuestr: 168*cda5da8dSAndroid Build Coastguard Worker line = "%s\n" % etype 169*cda5da8dSAndroid Build Coastguard Worker else: 170*cda5da8dSAndroid Build Coastguard Worker line = "%s: %s\n" % (etype, valuestr) 171*cda5da8dSAndroid Build Coastguard Worker return line 172*cda5da8dSAndroid Build Coastguard Worker 173*cda5da8dSAndroid Build Coastguard Workerdef _safe_string(value, what, func=str): 174*cda5da8dSAndroid Build Coastguard Worker try: 175*cda5da8dSAndroid Build Coastguard Worker return func(value) 176*cda5da8dSAndroid Build Coastguard Worker except: 177*cda5da8dSAndroid Build Coastguard Worker return f'<{what} {func.__name__}() failed>' 178*cda5da8dSAndroid Build Coastguard Worker 179*cda5da8dSAndroid Build Coastguard Worker# -- 180*cda5da8dSAndroid Build Coastguard Worker 181*cda5da8dSAndroid Build Coastguard Workerdef print_exc(limit=None, file=None, chain=True): 182*cda5da8dSAndroid Build Coastguard Worker """Shorthand for 'print_exception(*sys.exc_info(), limit, file)'.""" 183*cda5da8dSAndroid Build Coastguard Worker print_exception(*sys.exc_info(), limit=limit, file=file, chain=chain) 184*cda5da8dSAndroid Build Coastguard Worker 185*cda5da8dSAndroid Build Coastguard Workerdef format_exc(limit=None, chain=True): 186*cda5da8dSAndroid Build Coastguard Worker """Like print_exc() but return a string.""" 187*cda5da8dSAndroid Build Coastguard Worker return "".join(format_exception(*sys.exc_info(), limit=limit, chain=chain)) 188*cda5da8dSAndroid Build Coastguard Worker 189*cda5da8dSAndroid Build Coastguard Workerdef print_last(limit=None, file=None, chain=True): 190*cda5da8dSAndroid Build Coastguard Worker """This is a shorthand for 'print_exception(sys.last_type, 191*cda5da8dSAndroid Build Coastguard Worker sys.last_value, sys.last_traceback, limit, file)'.""" 192*cda5da8dSAndroid Build Coastguard Worker if not hasattr(sys, "last_type"): 193*cda5da8dSAndroid Build Coastguard Worker raise ValueError("no last exception") 194*cda5da8dSAndroid Build Coastguard Worker print_exception(sys.last_type, sys.last_value, sys.last_traceback, 195*cda5da8dSAndroid Build Coastguard Worker limit, file, chain) 196*cda5da8dSAndroid Build Coastguard Worker 197*cda5da8dSAndroid Build Coastguard Worker# 198*cda5da8dSAndroid Build Coastguard Worker# Printing and Extracting Stacks. 199*cda5da8dSAndroid Build Coastguard Worker# 200*cda5da8dSAndroid Build Coastguard Worker 201*cda5da8dSAndroid Build Coastguard Workerdef print_stack(f=None, limit=None, file=None): 202*cda5da8dSAndroid Build Coastguard Worker """Print a stack trace from its invocation point. 203*cda5da8dSAndroid Build Coastguard Worker 204*cda5da8dSAndroid Build Coastguard Worker The optional 'f' argument can be used to specify an alternate 205*cda5da8dSAndroid Build Coastguard Worker stack frame at which to start. The optional 'limit' and 'file' 206*cda5da8dSAndroid Build Coastguard Worker arguments have the same meaning as for print_exception(). 207*cda5da8dSAndroid Build Coastguard Worker """ 208*cda5da8dSAndroid Build Coastguard Worker if f is None: 209*cda5da8dSAndroid Build Coastguard Worker f = sys._getframe().f_back 210*cda5da8dSAndroid Build Coastguard Worker print_list(extract_stack(f, limit=limit), file=file) 211*cda5da8dSAndroid Build Coastguard Worker 212*cda5da8dSAndroid Build Coastguard Worker 213*cda5da8dSAndroid Build Coastguard Workerdef format_stack(f=None, limit=None): 214*cda5da8dSAndroid Build Coastguard Worker """Shorthand for 'format_list(extract_stack(f, limit))'.""" 215*cda5da8dSAndroid Build Coastguard Worker if f is None: 216*cda5da8dSAndroid Build Coastguard Worker f = sys._getframe().f_back 217*cda5da8dSAndroid Build Coastguard Worker return format_list(extract_stack(f, limit=limit)) 218*cda5da8dSAndroid Build Coastguard Worker 219*cda5da8dSAndroid Build Coastguard Worker 220*cda5da8dSAndroid Build Coastguard Workerdef extract_stack(f=None, limit=None): 221*cda5da8dSAndroid Build Coastguard Worker """Extract the raw traceback from the current stack frame. 222*cda5da8dSAndroid Build Coastguard Worker 223*cda5da8dSAndroid Build Coastguard Worker The return value has the same format as for extract_tb(). The 224*cda5da8dSAndroid Build Coastguard Worker optional 'f' and 'limit' arguments have the same meaning as for 225*cda5da8dSAndroid Build Coastguard Worker print_stack(). Each item in the list is a quadruple (filename, 226*cda5da8dSAndroid Build Coastguard Worker line number, function name, text), and the entries are in order 227*cda5da8dSAndroid Build Coastguard Worker from oldest to newest stack frame. 228*cda5da8dSAndroid Build Coastguard Worker """ 229*cda5da8dSAndroid Build Coastguard Worker if f is None: 230*cda5da8dSAndroid Build Coastguard Worker f = sys._getframe().f_back 231*cda5da8dSAndroid Build Coastguard Worker stack = StackSummary.extract(walk_stack(f), limit=limit) 232*cda5da8dSAndroid Build Coastguard Worker stack.reverse() 233*cda5da8dSAndroid Build Coastguard Worker return stack 234*cda5da8dSAndroid Build Coastguard Worker 235*cda5da8dSAndroid Build Coastguard Worker 236*cda5da8dSAndroid Build Coastguard Workerdef clear_frames(tb): 237*cda5da8dSAndroid Build Coastguard Worker "Clear all references to local variables in the frames of a traceback." 238*cda5da8dSAndroid Build Coastguard Worker while tb is not None: 239*cda5da8dSAndroid Build Coastguard Worker try: 240*cda5da8dSAndroid Build Coastguard Worker tb.tb_frame.clear() 241*cda5da8dSAndroid Build Coastguard Worker except RuntimeError: 242*cda5da8dSAndroid Build Coastguard Worker # Ignore the exception raised if the frame is still executing. 243*cda5da8dSAndroid Build Coastguard Worker pass 244*cda5da8dSAndroid Build Coastguard Worker tb = tb.tb_next 245*cda5da8dSAndroid Build Coastguard Worker 246*cda5da8dSAndroid Build Coastguard Worker 247*cda5da8dSAndroid Build Coastguard Workerclass FrameSummary: 248*cda5da8dSAndroid Build Coastguard Worker """Information about a single frame from a traceback. 249*cda5da8dSAndroid Build Coastguard Worker 250*cda5da8dSAndroid Build Coastguard Worker - :attr:`filename` The filename for the frame. 251*cda5da8dSAndroid Build Coastguard Worker - :attr:`lineno` The line within filename for the frame that was 252*cda5da8dSAndroid Build Coastguard Worker active when the frame was captured. 253*cda5da8dSAndroid Build Coastguard Worker - :attr:`name` The name of the function or method that was executing 254*cda5da8dSAndroid Build Coastguard Worker when the frame was captured. 255*cda5da8dSAndroid Build Coastguard Worker - :attr:`line` The text from the linecache module for the 256*cda5da8dSAndroid Build Coastguard Worker of code that was running when the frame was captured. 257*cda5da8dSAndroid Build Coastguard Worker - :attr:`locals` Either None if locals were not supplied, or a dict 258*cda5da8dSAndroid Build Coastguard Worker mapping the name to the repr() of the variable. 259*cda5da8dSAndroid Build Coastguard Worker """ 260*cda5da8dSAndroid Build Coastguard Worker 261*cda5da8dSAndroid Build Coastguard Worker __slots__ = ('filename', 'lineno', 'end_lineno', 'colno', 'end_colno', 262*cda5da8dSAndroid Build Coastguard Worker 'name', '_line', 'locals') 263*cda5da8dSAndroid Build Coastguard Worker 264*cda5da8dSAndroid Build Coastguard Worker def __init__(self, filename, lineno, name, *, lookup_line=True, 265*cda5da8dSAndroid Build Coastguard Worker locals=None, line=None, 266*cda5da8dSAndroid Build Coastguard Worker end_lineno=None, colno=None, end_colno=None): 267*cda5da8dSAndroid Build Coastguard Worker """Construct a FrameSummary. 268*cda5da8dSAndroid Build Coastguard Worker 269*cda5da8dSAndroid Build Coastguard Worker :param lookup_line: If True, `linecache` is consulted for the source 270*cda5da8dSAndroid Build Coastguard Worker code line. Otherwise, the line will be looked up when first needed. 271*cda5da8dSAndroid Build Coastguard Worker :param locals: If supplied the frame locals, which will be captured as 272*cda5da8dSAndroid Build Coastguard Worker object representations. 273*cda5da8dSAndroid Build Coastguard Worker :param line: If provided, use this instead of looking up the line in 274*cda5da8dSAndroid Build Coastguard Worker the linecache. 275*cda5da8dSAndroid Build Coastguard Worker """ 276*cda5da8dSAndroid Build Coastguard Worker self.filename = filename 277*cda5da8dSAndroid Build Coastguard Worker self.lineno = lineno 278*cda5da8dSAndroid Build Coastguard Worker self.name = name 279*cda5da8dSAndroid Build Coastguard Worker self._line = line 280*cda5da8dSAndroid Build Coastguard Worker if lookup_line: 281*cda5da8dSAndroid Build Coastguard Worker self.line 282*cda5da8dSAndroid Build Coastguard Worker self.locals = {k: repr(v) for k, v in locals.items()} if locals else None 283*cda5da8dSAndroid Build Coastguard Worker self.end_lineno = end_lineno 284*cda5da8dSAndroid Build Coastguard Worker self.colno = colno 285*cda5da8dSAndroid Build Coastguard Worker self.end_colno = end_colno 286*cda5da8dSAndroid Build Coastguard Worker 287*cda5da8dSAndroid Build Coastguard Worker def __eq__(self, other): 288*cda5da8dSAndroid Build Coastguard Worker if isinstance(other, FrameSummary): 289*cda5da8dSAndroid Build Coastguard Worker return (self.filename == other.filename and 290*cda5da8dSAndroid Build Coastguard Worker self.lineno == other.lineno and 291*cda5da8dSAndroid Build Coastguard Worker self.name == other.name and 292*cda5da8dSAndroid Build Coastguard Worker self.locals == other.locals) 293*cda5da8dSAndroid Build Coastguard Worker if isinstance(other, tuple): 294*cda5da8dSAndroid Build Coastguard Worker return (self.filename, self.lineno, self.name, self.line) == other 295*cda5da8dSAndroid Build Coastguard Worker return NotImplemented 296*cda5da8dSAndroid Build Coastguard Worker 297*cda5da8dSAndroid Build Coastguard Worker def __getitem__(self, pos): 298*cda5da8dSAndroid Build Coastguard Worker return (self.filename, self.lineno, self.name, self.line)[pos] 299*cda5da8dSAndroid Build Coastguard Worker 300*cda5da8dSAndroid Build Coastguard Worker def __iter__(self): 301*cda5da8dSAndroid Build Coastguard Worker return iter([self.filename, self.lineno, self.name, self.line]) 302*cda5da8dSAndroid Build Coastguard Worker 303*cda5da8dSAndroid Build Coastguard Worker def __repr__(self): 304*cda5da8dSAndroid Build Coastguard Worker return "<FrameSummary file {filename}, line {lineno} in {name}>".format( 305*cda5da8dSAndroid Build Coastguard Worker filename=self.filename, lineno=self.lineno, name=self.name) 306*cda5da8dSAndroid Build Coastguard Worker 307*cda5da8dSAndroid Build Coastguard Worker def __len__(self): 308*cda5da8dSAndroid Build Coastguard Worker return 4 309*cda5da8dSAndroid Build Coastguard Worker 310*cda5da8dSAndroid Build Coastguard Worker @property 311*cda5da8dSAndroid Build Coastguard Worker def _original_line(self): 312*cda5da8dSAndroid Build Coastguard Worker # Returns the line as-is from the source, without modifying whitespace. 313*cda5da8dSAndroid Build Coastguard Worker self.line 314*cda5da8dSAndroid Build Coastguard Worker return self._line 315*cda5da8dSAndroid Build Coastguard Worker 316*cda5da8dSAndroid Build Coastguard Worker @property 317*cda5da8dSAndroid Build Coastguard Worker def line(self): 318*cda5da8dSAndroid Build Coastguard Worker if self._line is None: 319*cda5da8dSAndroid Build Coastguard Worker if self.lineno is None: 320*cda5da8dSAndroid Build Coastguard Worker return None 321*cda5da8dSAndroid Build Coastguard Worker self._line = linecache.getline(self.filename, self.lineno) 322*cda5da8dSAndroid Build Coastguard Worker return self._line.strip() 323*cda5da8dSAndroid Build Coastguard Worker 324*cda5da8dSAndroid Build Coastguard Worker 325*cda5da8dSAndroid Build Coastguard Workerdef walk_stack(f): 326*cda5da8dSAndroid Build Coastguard Worker """Walk a stack yielding the frame and line number for each frame. 327*cda5da8dSAndroid Build Coastguard Worker 328*cda5da8dSAndroid Build Coastguard Worker This will follow f.f_back from the given frame. If no frame is given, the 329*cda5da8dSAndroid Build Coastguard Worker current stack is used. Usually used with StackSummary.extract. 330*cda5da8dSAndroid Build Coastguard Worker """ 331*cda5da8dSAndroid Build Coastguard Worker if f is None: 332*cda5da8dSAndroid Build Coastguard Worker f = sys._getframe().f_back.f_back.f_back.f_back 333*cda5da8dSAndroid Build Coastguard Worker while f is not None: 334*cda5da8dSAndroid Build Coastguard Worker yield f, f.f_lineno 335*cda5da8dSAndroid Build Coastguard Worker f = f.f_back 336*cda5da8dSAndroid Build Coastguard Worker 337*cda5da8dSAndroid Build Coastguard Worker 338*cda5da8dSAndroid Build Coastguard Workerdef walk_tb(tb): 339*cda5da8dSAndroid Build Coastguard Worker """Walk a traceback yielding the frame and line number for each frame. 340*cda5da8dSAndroid Build Coastguard Worker 341*cda5da8dSAndroid Build Coastguard Worker This will follow tb.tb_next (and thus is in the opposite order to 342*cda5da8dSAndroid Build Coastguard Worker walk_stack). Usually used with StackSummary.extract. 343*cda5da8dSAndroid Build Coastguard Worker """ 344*cda5da8dSAndroid Build Coastguard Worker while tb is not None: 345*cda5da8dSAndroid Build Coastguard Worker yield tb.tb_frame, tb.tb_lineno 346*cda5da8dSAndroid Build Coastguard Worker tb = tb.tb_next 347*cda5da8dSAndroid Build Coastguard Worker 348*cda5da8dSAndroid Build Coastguard Worker 349*cda5da8dSAndroid Build Coastguard Workerdef _walk_tb_with_full_positions(tb): 350*cda5da8dSAndroid Build Coastguard Worker # Internal version of walk_tb that yields full code positions including 351*cda5da8dSAndroid Build Coastguard Worker # end line and column information. 352*cda5da8dSAndroid Build Coastguard Worker while tb is not None: 353*cda5da8dSAndroid Build Coastguard Worker positions = _get_code_position(tb.tb_frame.f_code, tb.tb_lasti) 354*cda5da8dSAndroid Build Coastguard Worker # Yield tb_lineno when co_positions does not have a line number to 355*cda5da8dSAndroid Build Coastguard Worker # maintain behavior with walk_tb. 356*cda5da8dSAndroid Build Coastguard Worker if positions[0] is None: 357*cda5da8dSAndroid Build Coastguard Worker yield tb.tb_frame, (tb.tb_lineno, ) + positions[1:] 358*cda5da8dSAndroid Build Coastguard Worker else: 359*cda5da8dSAndroid Build Coastguard Worker yield tb.tb_frame, positions 360*cda5da8dSAndroid Build Coastguard Worker tb = tb.tb_next 361*cda5da8dSAndroid Build Coastguard Worker 362*cda5da8dSAndroid Build Coastguard Worker 363*cda5da8dSAndroid Build Coastguard Workerdef _get_code_position(code, instruction_index): 364*cda5da8dSAndroid Build Coastguard Worker if instruction_index < 0: 365*cda5da8dSAndroid Build Coastguard Worker return (None, None, None, None) 366*cda5da8dSAndroid Build Coastguard Worker positions_gen = code.co_positions() 367*cda5da8dSAndroid Build Coastguard Worker return next(itertools.islice(positions_gen, instruction_index // 2, None)) 368*cda5da8dSAndroid Build Coastguard Worker 369*cda5da8dSAndroid Build Coastguard Worker 370*cda5da8dSAndroid Build Coastguard Worker_RECURSIVE_CUTOFF = 3 # Also hardcoded in traceback.c. 371*cda5da8dSAndroid Build Coastguard Worker 372*cda5da8dSAndroid Build Coastguard Workerclass StackSummary(list): 373*cda5da8dSAndroid Build Coastguard Worker """A list of FrameSummary objects, representing a stack of frames.""" 374*cda5da8dSAndroid Build Coastguard Worker 375*cda5da8dSAndroid Build Coastguard Worker @classmethod 376*cda5da8dSAndroid Build Coastguard Worker def extract(klass, frame_gen, *, limit=None, lookup_lines=True, 377*cda5da8dSAndroid Build Coastguard Worker capture_locals=False): 378*cda5da8dSAndroid Build Coastguard Worker """Create a StackSummary from a traceback or stack object. 379*cda5da8dSAndroid Build Coastguard Worker 380*cda5da8dSAndroid Build Coastguard Worker :param frame_gen: A generator that yields (frame, lineno) tuples 381*cda5da8dSAndroid Build Coastguard Worker whose summaries are to be included in the stack. 382*cda5da8dSAndroid Build Coastguard Worker :param limit: None to include all frames or the number of frames to 383*cda5da8dSAndroid Build Coastguard Worker include. 384*cda5da8dSAndroid Build Coastguard Worker :param lookup_lines: If True, lookup lines for each frame immediately, 385*cda5da8dSAndroid Build Coastguard Worker otherwise lookup is deferred until the frame is rendered. 386*cda5da8dSAndroid Build Coastguard Worker :param capture_locals: If True, the local variables from each frame will 387*cda5da8dSAndroid Build Coastguard Worker be captured as object representations into the FrameSummary. 388*cda5da8dSAndroid Build Coastguard Worker """ 389*cda5da8dSAndroid Build Coastguard Worker def extended_frame_gen(): 390*cda5da8dSAndroid Build Coastguard Worker for f, lineno in frame_gen: 391*cda5da8dSAndroid Build Coastguard Worker yield f, (lineno, None, None, None) 392*cda5da8dSAndroid Build Coastguard Worker 393*cda5da8dSAndroid Build Coastguard Worker return klass._extract_from_extended_frame_gen( 394*cda5da8dSAndroid Build Coastguard Worker extended_frame_gen(), limit=limit, lookup_lines=lookup_lines, 395*cda5da8dSAndroid Build Coastguard Worker capture_locals=capture_locals) 396*cda5da8dSAndroid Build Coastguard Worker 397*cda5da8dSAndroid Build Coastguard Worker @classmethod 398*cda5da8dSAndroid Build Coastguard Worker def _extract_from_extended_frame_gen(klass, frame_gen, *, limit=None, 399*cda5da8dSAndroid Build Coastguard Worker lookup_lines=True, capture_locals=False): 400*cda5da8dSAndroid Build Coastguard Worker # Same as extract but operates on a frame generator that yields 401*cda5da8dSAndroid Build Coastguard Worker # (frame, (lineno, end_lineno, colno, end_colno)) in the stack. 402*cda5da8dSAndroid Build Coastguard Worker # Only lineno is required, the remaining fields can be None if the 403*cda5da8dSAndroid Build Coastguard Worker # information is not available. 404*cda5da8dSAndroid Build Coastguard Worker if limit is None: 405*cda5da8dSAndroid Build Coastguard Worker limit = getattr(sys, 'tracebacklimit', None) 406*cda5da8dSAndroid Build Coastguard Worker if limit is not None and limit < 0: 407*cda5da8dSAndroid Build Coastguard Worker limit = 0 408*cda5da8dSAndroid Build Coastguard Worker if limit is not None: 409*cda5da8dSAndroid Build Coastguard Worker if limit >= 0: 410*cda5da8dSAndroid Build Coastguard Worker frame_gen = itertools.islice(frame_gen, limit) 411*cda5da8dSAndroid Build Coastguard Worker else: 412*cda5da8dSAndroid Build Coastguard Worker frame_gen = collections.deque(frame_gen, maxlen=-limit) 413*cda5da8dSAndroid Build Coastguard Worker 414*cda5da8dSAndroid Build Coastguard Worker result = klass() 415*cda5da8dSAndroid Build Coastguard Worker fnames = set() 416*cda5da8dSAndroid Build Coastguard Worker for f, (lineno, end_lineno, colno, end_colno) in frame_gen: 417*cda5da8dSAndroid Build Coastguard Worker co = f.f_code 418*cda5da8dSAndroid Build Coastguard Worker filename = co.co_filename 419*cda5da8dSAndroid Build Coastguard Worker name = co.co_name 420*cda5da8dSAndroid Build Coastguard Worker 421*cda5da8dSAndroid Build Coastguard Worker fnames.add(filename) 422*cda5da8dSAndroid Build Coastguard Worker linecache.lazycache(filename, f.f_globals) 423*cda5da8dSAndroid Build Coastguard Worker # Must defer line lookups until we have called checkcache. 424*cda5da8dSAndroid Build Coastguard Worker if capture_locals: 425*cda5da8dSAndroid Build Coastguard Worker f_locals = f.f_locals 426*cda5da8dSAndroid Build Coastguard Worker else: 427*cda5da8dSAndroid Build Coastguard Worker f_locals = None 428*cda5da8dSAndroid Build Coastguard Worker result.append(FrameSummary( 429*cda5da8dSAndroid Build Coastguard Worker filename, lineno, name, lookup_line=False, locals=f_locals, 430*cda5da8dSAndroid Build Coastguard Worker end_lineno=end_lineno, colno=colno, end_colno=end_colno)) 431*cda5da8dSAndroid Build Coastguard Worker for filename in fnames: 432*cda5da8dSAndroid Build Coastguard Worker linecache.checkcache(filename) 433*cda5da8dSAndroid Build Coastguard Worker # If immediate lookup was desired, trigger lookups now. 434*cda5da8dSAndroid Build Coastguard Worker if lookup_lines: 435*cda5da8dSAndroid Build Coastguard Worker for f in result: 436*cda5da8dSAndroid Build Coastguard Worker f.line 437*cda5da8dSAndroid Build Coastguard Worker return result 438*cda5da8dSAndroid Build Coastguard Worker 439*cda5da8dSAndroid Build Coastguard Worker @classmethod 440*cda5da8dSAndroid Build Coastguard Worker def from_list(klass, a_list): 441*cda5da8dSAndroid Build Coastguard Worker """ 442*cda5da8dSAndroid Build Coastguard Worker Create a StackSummary object from a supplied list of 443*cda5da8dSAndroid Build Coastguard Worker FrameSummary objects or old-style list of tuples. 444*cda5da8dSAndroid Build Coastguard Worker """ 445*cda5da8dSAndroid Build Coastguard Worker # While doing a fast-path check for isinstance(a_list, StackSummary) is 446*cda5da8dSAndroid Build Coastguard Worker # appealing, idlelib.run.cleanup_traceback and other similar code may 447*cda5da8dSAndroid Build Coastguard Worker # break this by making arbitrary frames plain tuples, so we need to 448*cda5da8dSAndroid Build Coastguard Worker # check on a frame by frame basis. 449*cda5da8dSAndroid Build Coastguard Worker result = StackSummary() 450*cda5da8dSAndroid Build Coastguard Worker for frame in a_list: 451*cda5da8dSAndroid Build Coastguard Worker if isinstance(frame, FrameSummary): 452*cda5da8dSAndroid Build Coastguard Worker result.append(frame) 453*cda5da8dSAndroid Build Coastguard Worker else: 454*cda5da8dSAndroid Build Coastguard Worker filename, lineno, name, line = frame 455*cda5da8dSAndroid Build Coastguard Worker result.append(FrameSummary(filename, lineno, name, line=line)) 456*cda5da8dSAndroid Build Coastguard Worker return result 457*cda5da8dSAndroid Build Coastguard Worker 458*cda5da8dSAndroid Build Coastguard Worker def format_frame_summary(self, frame_summary): 459*cda5da8dSAndroid Build Coastguard Worker """Format the lines for a single FrameSummary. 460*cda5da8dSAndroid Build Coastguard Worker 461*cda5da8dSAndroid Build Coastguard Worker Returns a string representing one frame involved in the stack. This 462*cda5da8dSAndroid Build Coastguard Worker gets called for every frame to be printed in the stack summary. 463*cda5da8dSAndroid Build Coastguard Worker """ 464*cda5da8dSAndroid Build Coastguard Worker row = [] 465*cda5da8dSAndroid Build Coastguard Worker row.append(' File "{}", line {}, in {}\n'.format( 466*cda5da8dSAndroid Build Coastguard Worker frame_summary.filename, frame_summary.lineno, frame_summary.name)) 467*cda5da8dSAndroid Build Coastguard Worker if frame_summary.line: 468*cda5da8dSAndroid Build Coastguard Worker stripped_line = frame_summary.line.strip() 469*cda5da8dSAndroid Build Coastguard Worker row.append(' {}\n'.format(stripped_line)) 470*cda5da8dSAndroid Build Coastguard Worker 471*cda5da8dSAndroid Build Coastguard Worker orig_line_len = len(frame_summary._original_line) 472*cda5da8dSAndroid Build Coastguard Worker frame_line_len = len(frame_summary.line.lstrip()) 473*cda5da8dSAndroid Build Coastguard Worker stripped_characters = orig_line_len - frame_line_len 474*cda5da8dSAndroid Build Coastguard Worker if ( 475*cda5da8dSAndroid Build Coastguard Worker frame_summary.colno is not None 476*cda5da8dSAndroid Build Coastguard Worker and frame_summary.end_colno is not None 477*cda5da8dSAndroid Build Coastguard Worker ): 478*cda5da8dSAndroid Build Coastguard Worker start_offset = _byte_offset_to_character_offset( 479*cda5da8dSAndroid Build Coastguard Worker frame_summary._original_line, frame_summary.colno) + 1 480*cda5da8dSAndroid Build Coastguard Worker end_offset = _byte_offset_to_character_offset( 481*cda5da8dSAndroid Build Coastguard Worker frame_summary._original_line, frame_summary.end_colno) + 1 482*cda5da8dSAndroid Build Coastguard Worker 483*cda5da8dSAndroid Build Coastguard Worker anchors = None 484*cda5da8dSAndroid Build Coastguard Worker if frame_summary.lineno == frame_summary.end_lineno: 485*cda5da8dSAndroid Build Coastguard Worker with suppress(Exception): 486*cda5da8dSAndroid Build Coastguard Worker anchors = _extract_caret_anchors_from_line_segment( 487*cda5da8dSAndroid Build Coastguard Worker frame_summary._original_line[start_offset - 1:end_offset - 1] 488*cda5da8dSAndroid Build Coastguard Worker ) 489*cda5da8dSAndroid Build Coastguard Worker else: 490*cda5da8dSAndroid Build Coastguard Worker end_offset = stripped_characters + len(stripped_line) 491*cda5da8dSAndroid Build Coastguard Worker 492*cda5da8dSAndroid Build Coastguard Worker # show indicators if primary char doesn't span the frame line 493*cda5da8dSAndroid Build Coastguard Worker if end_offset - start_offset < len(stripped_line) or ( 494*cda5da8dSAndroid Build Coastguard Worker anchors and anchors.right_start_offset - anchors.left_end_offset > 0): 495*cda5da8dSAndroid Build Coastguard Worker row.append(' ') 496*cda5da8dSAndroid Build Coastguard Worker row.append(' ' * (start_offset - stripped_characters)) 497*cda5da8dSAndroid Build Coastguard Worker 498*cda5da8dSAndroid Build Coastguard Worker if anchors: 499*cda5da8dSAndroid Build Coastguard Worker row.append(anchors.primary_char * (anchors.left_end_offset)) 500*cda5da8dSAndroid Build Coastguard Worker row.append(anchors.secondary_char * (anchors.right_start_offset - anchors.left_end_offset)) 501*cda5da8dSAndroid Build Coastguard Worker row.append(anchors.primary_char * (end_offset - start_offset - anchors.right_start_offset)) 502*cda5da8dSAndroid Build Coastguard Worker else: 503*cda5da8dSAndroid Build Coastguard Worker row.append('^' * (end_offset - start_offset)) 504*cda5da8dSAndroid Build Coastguard Worker 505*cda5da8dSAndroid Build Coastguard Worker row.append('\n') 506*cda5da8dSAndroid Build Coastguard Worker 507*cda5da8dSAndroid Build Coastguard Worker if frame_summary.locals: 508*cda5da8dSAndroid Build Coastguard Worker for name, value in sorted(frame_summary.locals.items()): 509*cda5da8dSAndroid Build Coastguard Worker row.append(' {name} = {value}\n'.format(name=name, value=value)) 510*cda5da8dSAndroid Build Coastguard Worker 511*cda5da8dSAndroid Build Coastguard Worker return ''.join(row) 512*cda5da8dSAndroid Build Coastguard Worker 513*cda5da8dSAndroid Build Coastguard Worker def format(self): 514*cda5da8dSAndroid Build Coastguard Worker """Format the stack ready for printing. 515*cda5da8dSAndroid Build Coastguard Worker 516*cda5da8dSAndroid Build Coastguard Worker Returns a list of strings ready for printing. Each string in the 517*cda5da8dSAndroid Build Coastguard Worker resulting list corresponds to a single frame from the stack. 518*cda5da8dSAndroid Build Coastguard Worker Each string ends in a newline; the strings may contain internal 519*cda5da8dSAndroid Build Coastguard Worker newlines as well, for those items with source text lines. 520*cda5da8dSAndroid Build Coastguard Worker 521*cda5da8dSAndroid Build Coastguard Worker For long sequences of the same frame and line, the first few 522*cda5da8dSAndroid Build Coastguard Worker repetitions are shown, followed by a summary line stating the exact 523*cda5da8dSAndroid Build Coastguard Worker number of further repetitions. 524*cda5da8dSAndroid Build Coastguard Worker """ 525*cda5da8dSAndroid Build Coastguard Worker result = [] 526*cda5da8dSAndroid Build Coastguard Worker last_file = None 527*cda5da8dSAndroid Build Coastguard Worker last_line = None 528*cda5da8dSAndroid Build Coastguard Worker last_name = None 529*cda5da8dSAndroid Build Coastguard Worker count = 0 530*cda5da8dSAndroid Build Coastguard Worker for frame_summary in self: 531*cda5da8dSAndroid Build Coastguard Worker formatted_frame = self.format_frame_summary(frame_summary) 532*cda5da8dSAndroid Build Coastguard Worker if formatted_frame is None: 533*cda5da8dSAndroid Build Coastguard Worker continue 534*cda5da8dSAndroid Build Coastguard Worker if (last_file is None or last_file != frame_summary.filename or 535*cda5da8dSAndroid Build Coastguard Worker last_line is None or last_line != frame_summary.lineno or 536*cda5da8dSAndroid Build Coastguard Worker last_name is None or last_name != frame_summary.name): 537*cda5da8dSAndroid Build Coastguard Worker if count > _RECURSIVE_CUTOFF: 538*cda5da8dSAndroid Build Coastguard Worker count -= _RECURSIVE_CUTOFF 539*cda5da8dSAndroid Build Coastguard Worker result.append( 540*cda5da8dSAndroid Build Coastguard Worker f' [Previous line repeated {count} more ' 541*cda5da8dSAndroid Build Coastguard Worker f'time{"s" if count > 1 else ""}]\n' 542*cda5da8dSAndroid Build Coastguard Worker ) 543*cda5da8dSAndroid Build Coastguard Worker last_file = frame_summary.filename 544*cda5da8dSAndroid Build Coastguard Worker last_line = frame_summary.lineno 545*cda5da8dSAndroid Build Coastguard Worker last_name = frame_summary.name 546*cda5da8dSAndroid Build Coastguard Worker count = 0 547*cda5da8dSAndroid Build Coastguard Worker count += 1 548*cda5da8dSAndroid Build Coastguard Worker if count > _RECURSIVE_CUTOFF: 549*cda5da8dSAndroid Build Coastguard Worker continue 550*cda5da8dSAndroid Build Coastguard Worker result.append(formatted_frame) 551*cda5da8dSAndroid Build Coastguard Worker 552*cda5da8dSAndroid Build Coastguard Worker if count > _RECURSIVE_CUTOFF: 553*cda5da8dSAndroid Build Coastguard Worker count -= _RECURSIVE_CUTOFF 554*cda5da8dSAndroid Build Coastguard Worker result.append( 555*cda5da8dSAndroid Build Coastguard Worker f' [Previous line repeated {count} more ' 556*cda5da8dSAndroid Build Coastguard Worker f'time{"s" if count > 1 else ""}]\n' 557*cda5da8dSAndroid Build Coastguard Worker ) 558*cda5da8dSAndroid Build Coastguard Worker return result 559*cda5da8dSAndroid Build Coastguard Worker 560*cda5da8dSAndroid Build Coastguard Worker 561*cda5da8dSAndroid Build Coastguard Workerdef _byte_offset_to_character_offset(str, offset): 562*cda5da8dSAndroid Build Coastguard Worker as_utf8 = str.encode('utf-8') 563*cda5da8dSAndroid Build Coastguard Worker return len(as_utf8[:offset].decode("utf-8", errors="replace")) 564*cda5da8dSAndroid Build Coastguard Worker 565*cda5da8dSAndroid Build Coastguard Worker 566*cda5da8dSAndroid Build Coastguard Worker_Anchors = collections.namedtuple( 567*cda5da8dSAndroid Build Coastguard Worker "_Anchors", 568*cda5da8dSAndroid Build Coastguard Worker [ 569*cda5da8dSAndroid Build Coastguard Worker "left_end_offset", 570*cda5da8dSAndroid Build Coastguard Worker "right_start_offset", 571*cda5da8dSAndroid Build Coastguard Worker "primary_char", 572*cda5da8dSAndroid Build Coastguard Worker "secondary_char", 573*cda5da8dSAndroid Build Coastguard Worker ], 574*cda5da8dSAndroid Build Coastguard Worker defaults=["~", "^"] 575*cda5da8dSAndroid Build Coastguard Worker) 576*cda5da8dSAndroid Build Coastguard Worker 577*cda5da8dSAndroid Build Coastguard Workerdef _extract_caret_anchors_from_line_segment(segment): 578*cda5da8dSAndroid Build Coastguard Worker import ast 579*cda5da8dSAndroid Build Coastguard Worker 580*cda5da8dSAndroid Build Coastguard Worker try: 581*cda5da8dSAndroid Build Coastguard Worker tree = ast.parse(segment) 582*cda5da8dSAndroid Build Coastguard Worker except SyntaxError: 583*cda5da8dSAndroid Build Coastguard Worker return None 584*cda5da8dSAndroid Build Coastguard Worker 585*cda5da8dSAndroid Build Coastguard Worker if len(tree.body) != 1: 586*cda5da8dSAndroid Build Coastguard Worker return None 587*cda5da8dSAndroid Build Coastguard Worker 588*cda5da8dSAndroid Build Coastguard Worker normalize = lambda offset: _byte_offset_to_character_offset(segment, offset) 589*cda5da8dSAndroid Build Coastguard Worker statement = tree.body[0] 590*cda5da8dSAndroid Build Coastguard Worker match statement: 591*cda5da8dSAndroid Build Coastguard Worker case ast.Expr(expr): 592*cda5da8dSAndroid Build Coastguard Worker match expr: 593*cda5da8dSAndroid Build Coastguard Worker case ast.BinOp(): 594*cda5da8dSAndroid Build Coastguard Worker operator_start = normalize(expr.left.end_col_offset) 595*cda5da8dSAndroid Build Coastguard Worker operator_end = normalize(expr.right.col_offset) 596*cda5da8dSAndroid Build Coastguard Worker operator_str = segment[operator_start:operator_end] 597*cda5da8dSAndroid Build Coastguard Worker operator_offset = len(operator_str) - len(operator_str.lstrip()) 598*cda5da8dSAndroid Build Coastguard Worker 599*cda5da8dSAndroid Build Coastguard Worker left_anchor = expr.left.end_col_offset + operator_offset 600*cda5da8dSAndroid Build Coastguard Worker right_anchor = left_anchor + 1 601*cda5da8dSAndroid Build Coastguard Worker if ( 602*cda5da8dSAndroid Build Coastguard Worker operator_offset + 1 < len(operator_str) 603*cda5da8dSAndroid Build Coastguard Worker and not operator_str[operator_offset + 1].isspace() 604*cda5da8dSAndroid Build Coastguard Worker ): 605*cda5da8dSAndroid Build Coastguard Worker right_anchor += 1 606*cda5da8dSAndroid Build Coastguard Worker return _Anchors(normalize(left_anchor), normalize(right_anchor)) 607*cda5da8dSAndroid Build Coastguard Worker case ast.Subscript(): 608*cda5da8dSAndroid Build Coastguard Worker subscript_start = normalize(expr.value.end_col_offset) 609*cda5da8dSAndroid Build Coastguard Worker subscript_end = normalize(expr.slice.end_col_offset + 1) 610*cda5da8dSAndroid Build Coastguard Worker return _Anchors(subscript_start, subscript_end) 611*cda5da8dSAndroid Build Coastguard Worker 612*cda5da8dSAndroid Build Coastguard Worker return None 613*cda5da8dSAndroid Build Coastguard Worker 614*cda5da8dSAndroid Build Coastguard Worker 615*cda5da8dSAndroid Build Coastguard Workerclass _ExceptionPrintContext: 616*cda5da8dSAndroid Build Coastguard Worker def __init__(self): 617*cda5da8dSAndroid Build Coastguard Worker self.seen = set() 618*cda5da8dSAndroid Build Coastguard Worker self.exception_group_depth = 0 619*cda5da8dSAndroid Build Coastguard Worker self.need_close = False 620*cda5da8dSAndroid Build Coastguard Worker 621*cda5da8dSAndroid Build Coastguard Worker def indent(self): 622*cda5da8dSAndroid Build Coastguard Worker return ' ' * (2 * self.exception_group_depth) 623*cda5da8dSAndroid Build Coastguard Worker 624*cda5da8dSAndroid Build Coastguard Worker def emit(self, text_gen, margin_char=None): 625*cda5da8dSAndroid Build Coastguard Worker if margin_char is None: 626*cda5da8dSAndroid Build Coastguard Worker margin_char = '|' 627*cda5da8dSAndroid Build Coastguard Worker indent_str = self.indent() 628*cda5da8dSAndroid Build Coastguard Worker if self.exception_group_depth: 629*cda5da8dSAndroid Build Coastguard Worker indent_str += margin_char + ' ' 630*cda5da8dSAndroid Build Coastguard Worker 631*cda5da8dSAndroid Build Coastguard Worker if isinstance(text_gen, str): 632*cda5da8dSAndroid Build Coastguard Worker yield textwrap.indent(text_gen, indent_str, lambda line: True) 633*cda5da8dSAndroid Build Coastguard Worker else: 634*cda5da8dSAndroid Build Coastguard Worker for text in text_gen: 635*cda5da8dSAndroid Build Coastguard Worker yield textwrap.indent(text, indent_str, lambda line: True) 636*cda5da8dSAndroid Build Coastguard Worker 637*cda5da8dSAndroid Build Coastguard Worker 638*cda5da8dSAndroid Build Coastguard Workerclass TracebackException: 639*cda5da8dSAndroid Build Coastguard Worker """An exception ready for rendering. 640*cda5da8dSAndroid Build Coastguard Worker 641*cda5da8dSAndroid Build Coastguard Worker The traceback module captures enough attributes from the original exception 642*cda5da8dSAndroid Build Coastguard Worker to this intermediary form to ensure that no references are held, while 643*cda5da8dSAndroid Build Coastguard Worker still being able to fully print or format it. 644*cda5da8dSAndroid Build Coastguard Worker 645*cda5da8dSAndroid Build Coastguard Worker max_group_width and max_group_depth control the formatting of exception 646*cda5da8dSAndroid Build Coastguard Worker groups. The depth refers to the nesting level of the group, and the width 647*cda5da8dSAndroid Build Coastguard Worker refers to the size of a single exception group's exceptions array. The 648*cda5da8dSAndroid Build Coastguard Worker formatted output is truncated when either limit is exceeded. 649*cda5da8dSAndroid Build Coastguard Worker 650*cda5da8dSAndroid Build Coastguard Worker Use `from_exception` to create TracebackException instances from exception 651*cda5da8dSAndroid Build Coastguard Worker objects, or the constructor to create TracebackException instances from 652*cda5da8dSAndroid Build Coastguard Worker individual components. 653*cda5da8dSAndroid Build Coastguard Worker 654*cda5da8dSAndroid Build Coastguard Worker - :attr:`__cause__` A TracebackException of the original *__cause__*. 655*cda5da8dSAndroid Build Coastguard Worker - :attr:`__context__` A TracebackException of the original *__context__*. 656*cda5da8dSAndroid Build Coastguard Worker - :attr:`exceptions` For exception groups - a list of TracebackException 657*cda5da8dSAndroid Build Coastguard Worker instances for the nested *exceptions*. ``None`` for other exceptions. 658*cda5da8dSAndroid Build Coastguard Worker - :attr:`__suppress_context__` The *__suppress_context__* value from the 659*cda5da8dSAndroid Build Coastguard Worker original exception. 660*cda5da8dSAndroid Build Coastguard Worker - :attr:`stack` A `StackSummary` representing the traceback. 661*cda5da8dSAndroid Build Coastguard Worker - :attr:`exc_type` The class of the original traceback. 662*cda5da8dSAndroid Build Coastguard Worker - :attr:`filename` For syntax errors - the filename where the error 663*cda5da8dSAndroid Build Coastguard Worker occurred. 664*cda5da8dSAndroid Build Coastguard Worker - :attr:`lineno` For syntax errors - the linenumber where the error 665*cda5da8dSAndroid Build Coastguard Worker occurred. 666*cda5da8dSAndroid Build Coastguard Worker - :attr:`end_lineno` For syntax errors - the end linenumber where the error 667*cda5da8dSAndroid Build Coastguard Worker occurred. Can be `None` if not present. 668*cda5da8dSAndroid Build Coastguard Worker - :attr:`text` For syntax errors - the text where the error 669*cda5da8dSAndroid Build Coastguard Worker occurred. 670*cda5da8dSAndroid Build Coastguard Worker - :attr:`offset` For syntax errors - the offset into the text where the 671*cda5da8dSAndroid Build Coastguard Worker error occurred. 672*cda5da8dSAndroid Build Coastguard Worker - :attr:`end_offset` For syntax errors - the end offset into the text where 673*cda5da8dSAndroid Build Coastguard Worker the error occurred. Can be `None` if not present. 674*cda5da8dSAndroid Build Coastguard Worker - :attr:`msg` For syntax errors - the compiler error message. 675*cda5da8dSAndroid Build Coastguard Worker """ 676*cda5da8dSAndroid Build Coastguard Worker 677*cda5da8dSAndroid Build Coastguard Worker def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, 678*cda5da8dSAndroid Build Coastguard Worker lookup_lines=True, capture_locals=False, compact=False, 679*cda5da8dSAndroid Build Coastguard Worker max_group_width=15, max_group_depth=10, _seen=None): 680*cda5da8dSAndroid Build Coastguard Worker # NB: we need to accept exc_traceback, exc_value, exc_traceback to 681*cda5da8dSAndroid Build Coastguard Worker # permit backwards compat with the existing API, otherwise we 682*cda5da8dSAndroid Build Coastguard Worker # need stub thunk objects just to glue it together. 683*cda5da8dSAndroid Build Coastguard Worker # Handle loops in __cause__ or __context__. 684*cda5da8dSAndroid Build Coastguard Worker is_recursive_call = _seen is not None 685*cda5da8dSAndroid Build Coastguard Worker if _seen is None: 686*cda5da8dSAndroid Build Coastguard Worker _seen = set() 687*cda5da8dSAndroid Build Coastguard Worker _seen.add(id(exc_value)) 688*cda5da8dSAndroid Build Coastguard Worker 689*cda5da8dSAndroid Build Coastguard Worker self.max_group_width = max_group_width 690*cda5da8dSAndroid Build Coastguard Worker self.max_group_depth = max_group_depth 691*cda5da8dSAndroid Build Coastguard Worker 692*cda5da8dSAndroid Build Coastguard Worker self.stack = StackSummary._extract_from_extended_frame_gen( 693*cda5da8dSAndroid Build Coastguard Worker _walk_tb_with_full_positions(exc_traceback), 694*cda5da8dSAndroid Build Coastguard Worker limit=limit, lookup_lines=lookup_lines, 695*cda5da8dSAndroid Build Coastguard Worker capture_locals=capture_locals) 696*cda5da8dSAndroid Build Coastguard Worker self.exc_type = exc_type 697*cda5da8dSAndroid Build Coastguard Worker # Capture now to permit freeing resources: only complication is in the 698*cda5da8dSAndroid Build Coastguard Worker # unofficial API _format_final_exc_line 699*cda5da8dSAndroid Build Coastguard Worker self._str = _safe_string(exc_value, 'exception') 700*cda5da8dSAndroid Build Coastguard Worker self.__notes__ = getattr(exc_value, '__notes__', None) 701*cda5da8dSAndroid Build Coastguard Worker 702*cda5da8dSAndroid Build Coastguard Worker if exc_type and issubclass(exc_type, SyntaxError): 703*cda5da8dSAndroid Build Coastguard Worker # Handle SyntaxError's specially 704*cda5da8dSAndroid Build Coastguard Worker self.filename = exc_value.filename 705*cda5da8dSAndroid Build Coastguard Worker lno = exc_value.lineno 706*cda5da8dSAndroid Build Coastguard Worker self.lineno = str(lno) if lno is not None else None 707*cda5da8dSAndroid Build Coastguard Worker end_lno = exc_value.end_lineno 708*cda5da8dSAndroid Build Coastguard Worker self.end_lineno = str(end_lno) if end_lno is not None else None 709*cda5da8dSAndroid Build Coastguard Worker self.text = exc_value.text 710*cda5da8dSAndroid Build Coastguard Worker self.offset = exc_value.offset 711*cda5da8dSAndroid Build Coastguard Worker self.end_offset = exc_value.end_offset 712*cda5da8dSAndroid Build Coastguard Worker self.msg = exc_value.msg 713*cda5da8dSAndroid Build Coastguard Worker if lookup_lines: 714*cda5da8dSAndroid Build Coastguard Worker self._load_lines() 715*cda5da8dSAndroid Build Coastguard Worker self.__suppress_context__ = \ 716*cda5da8dSAndroid Build Coastguard Worker exc_value.__suppress_context__ if exc_value is not None else False 717*cda5da8dSAndroid Build Coastguard Worker 718*cda5da8dSAndroid Build Coastguard Worker # Convert __cause__ and __context__ to `TracebackExceptions`s, use a 719*cda5da8dSAndroid Build Coastguard Worker # queue to avoid recursion (only the top-level call gets _seen == None) 720*cda5da8dSAndroid Build Coastguard Worker if not is_recursive_call: 721*cda5da8dSAndroid Build Coastguard Worker queue = [(self, exc_value)] 722*cda5da8dSAndroid Build Coastguard Worker while queue: 723*cda5da8dSAndroid Build Coastguard Worker te, e = queue.pop() 724*cda5da8dSAndroid Build Coastguard Worker if (e and e.__cause__ is not None 725*cda5da8dSAndroid Build Coastguard Worker and id(e.__cause__) not in _seen): 726*cda5da8dSAndroid Build Coastguard Worker cause = TracebackException( 727*cda5da8dSAndroid Build Coastguard Worker type(e.__cause__), 728*cda5da8dSAndroid Build Coastguard Worker e.__cause__, 729*cda5da8dSAndroid Build Coastguard Worker e.__cause__.__traceback__, 730*cda5da8dSAndroid Build Coastguard Worker limit=limit, 731*cda5da8dSAndroid Build Coastguard Worker lookup_lines=lookup_lines, 732*cda5da8dSAndroid Build Coastguard Worker capture_locals=capture_locals, 733*cda5da8dSAndroid Build Coastguard Worker max_group_width=max_group_width, 734*cda5da8dSAndroid Build Coastguard Worker max_group_depth=max_group_depth, 735*cda5da8dSAndroid Build Coastguard Worker _seen=_seen) 736*cda5da8dSAndroid Build Coastguard Worker else: 737*cda5da8dSAndroid Build Coastguard Worker cause = None 738*cda5da8dSAndroid Build Coastguard Worker 739*cda5da8dSAndroid Build Coastguard Worker if compact: 740*cda5da8dSAndroid Build Coastguard Worker need_context = (cause is None and 741*cda5da8dSAndroid Build Coastguard Worker e is not None and 742*cda5da8dSAndroid Build Coastguard Worker not e.__suppress_context__) 743*cda5da8dSAndroid Build Coastguard Worker else: 744*cda5da8dSAndroid Build Coastguard Worker need_context = True 745*cda5da8dSAndroid Build Coastguard Worker if (e and e.__context__ is not None 746*cda5da8dSAndroid Build Coastguard Worker and need_context and id(e.__context__) not in _seen): 747*cda5da8dSAndroid Build Coastguard Worker context = TracebackException( 748*cda5da8dSAndroid Build Coastguard Worker type(e.__context__), 749*cda5da8dSAndroid Build Coastguard Worker e.__context__, 750*cda5da8dSAndroid Build Coastguard Worker e.__context__.__traceback__, 751*cda5da8dSAndroid Build Coastguard Worker limit=limit, 752*cda5da8dSAndroid Build Coastguard Worker lookup_lines=lookup_lines, 753*cda5da8dSAndroid Build Coastguard Worker capture_locals=capture_locals, 754*cda5da8dSAndroid Build Coastguard Worker max_group_width=max_group_width, 755*cda5da8dSAndroid Build Coastguard Worker max_group_depth=max_group_depth, 756*cda5da8dSAndroid Build Coastguard Worker _seen=_seen) 757*cda5da8dSAndroid Build Coastguard Worker else: 758*cda5da8dSAndroid Build Coastguard Worker context = None 759*cda5da8dSAndroid Build Coastguard Worker 760*cda5da8dSAndroid Build Coastguard Worker if e and isinstance(e, BaseExceptionGroup): 761*cda5da8dSAndroid Build Coastguard Worker exceptions = [] 762*cda5da8dSAndroid Build Coastguard Worker for exc in e.exceptions: 763*cda5da8dSAndroid Build Coastguard Worker texc = TracebackException( 764*cda5da8dSAndroid Build Coastguard Worker type(exc), 765*cda5da8dSAndroid Build Coastguard Worker exc, 766*cda5da8dSAndroid Build Coastguard Worker exc.__traceback__, 767*cda5da8dSAndroid Build Coastguard Worker limit=limit, 768*cda5da8dSAndroid Build Coastguard Worker lookup_lines=lookup_lines, 769*cda5da8dSAndroid Build Coastguard Worker capture_locals=capture_locals, 770*cda5da8dSAndroid Build Coastguard Worker max_group_width=max_group_width, 771*cda5da8dSAndroid Build Coastguard Worker max_group_depth=max_group_depth, 772*cda5da8dSAndroid Build Coastguard Worker _seen=_seen) 773*cda5da8dSAndroid Build Coastguard Worker exceptions.append(texc) 774*cda5da8dSAndroid Build Coastguard Worker else: 775*cda5da8dSAndroid Build Coastguard Worker exceptions = None 776*cda5da8dSAndroid Build Coastguard Worker 777*cda5da8dSAndroid Build Coastguard Worker te.__cause__ = cause 778*cda5da8dSAndroid Build Coastguard Worker te.__context__ = context 779*cda5da8dSAndroid Build Coastguard Worker te.exceptions = exceptions 780*cda5da8dSAndroid Build Coastguard Worker if cause: 781*cda5da8dSAndroid Build Coastguard Worker queue.append((te.__cause__, e.__cause__)) 782*cda5da8dSAndroid Build Coastguard Worker if context: 783*cda5da8dSAndroid Build Coastguard Worker queue.append((te.__context__, e.__context__)) 784*cda5da8dSAndroid Build Coastguard Worker if exceptions: 785*cda5da8dSAndroid Build Coastguard Worker queue.extend(zip(te.exceptions, e.exceptions)) 786*cda5da8dSAndroid Build Coastguard Worker 787*cda5da8dSAndroid Build Coastguard Worker @classmethod 788*cda5da8dSAndroid Build Coastguard Worker def from_exception(cls, exc, *args, **kwargs): 789*cda5da8dSAndroid Build Coastguard Worker """Create a TracebackException from an exception.""" 790*cda5da8dSAndroid Build Coastguard Worker return cls(type(exc), exc, exc.__traceback__, *args, **kwargs) 791*cda5da8dSAndroid Build Coastguard Worker 792*cda5da8dSAndroid Build Coastguard Worker def _load_lines(self): 793*cda5da8dSAndroid Build Coastguard Worker """Private API. force all lines in the stack to be loaded.""" 794*cda5da8dSAndroid Build Coastguard Worker for frame in self.stack: 795*cda5da8dSAndroid Build Coastguard Worker frame.line 796*cda5da8dSAndroid Build Coastguard Worker 797*cda5da8dSAndroid Build Coastguard Worker def __eq__(self, other): 798*cda5da8dSAndroid Build Coastguard Worker if isinstance(other, TracebackException): 799*cda5da8dSAndroid Build Coastguard Worker return self.__dict__ == other.__dict__ 800*cda5da8dSAndroid Build Coastguard Worker return NotImplemented 801*cda5da8dSAndroid Build Coastguard Worker 802*cda5da8dSAndroid Build Coastguard Worker def __str__(self): 803*cda5da8dSAndroid Build Coastguard Worker return self._str 804*cda5da8dSAndroid Build Coastguard Worker 805*cda5da8dSAndroid Build Coastguard Worker def format_exception_only(self): 806*cda5da8dSAndroid Build Coastguard Worker """Format the exception part of the traceback. 807*cda5da8dSAndroid Build Coastguard Worker 808*cda5da8dSAndroid Build Coastguard Worker The return value is a generator of strings, each ending in a newline. 809*cda5da8dSAndroid Build Coastguard Worker 810*cda5da8dSAndroid Build Coastguard Worker Normally, the generator emits a single string; however, for 811*cda5da8dSAndroid Build Coastguard Worker SyntaxError exceptions, it emits several lines that (when 812*cda5da8dSAndroid Build Coastguard Worker printed) display detailed information about where the syntax 813*cda5da8dSAndroid Build Coastguard Worker error occurred. 814*cda5da8dSAndroid Build Coastguard Worker 815*cda5da8dSAndroid Build Coastguard Worker The message indicating which exception occurred is always the last 816*cda5da8dSAndroid Build Coastguard Worker string in the output. 817*cda5da8dSAndroid Build Coastguard Worker """ 818*cda5da8dSAndroid Build Coastguard Worker if self.exc_type is None: 819*cda5da8dSAndroid Build Coastguard Worker yield _format_final_exc_line(None, self._str) 820*cda5da8dSAndroid Build Coastguard Worker return 821*cda5da8dSAndroid Build Coastguard Worker 822*cda5da8dSAndroid Build Coastguard Worker stype = self.exc_type.__qualname__ 823*cda5da8dSAndroid Build Coastguard Worker smod = self.exc_type.__module__ 824*cda5da8dSAndroid Build Coastguard Worker if smod not in ("__main__", "builtins"): 825*cda5da8dSAndroid Build Coastguard Worker if not isinstance(smod, str): 826*cda5da8dSAndroid Build Coastguard Worker smod = "<unknown>" 827*cda5da8dSAndroid Build Coastguard Worker stype = smod + '.' + stype 828*cda5da8dSAndroid Build Coastguard Worker 829*cda5da8dSAndroid Build Coastguard Worker if not issubclass(self.exc_type, SyntaxError): 830*cda5da8dSAndroid Build Coastguard Worker yield _format_final_exc_line(stype, self._str) 831*cda5da8dSAndroid Build Coastguard Worker else: 832*cda5da8dSAndroid Build Coastguard Worker yield from self._format_syntax_error(stype) 833*cda5da8dSAndroid Build Coastguard Worker if isinstance(self.__notes__, collections.abc.Sequence): 834*cda5da8dSAndroid Build Coastguard Worker for note in self.__notes__: 835*cda5da8dSAndroid Build Coastguard Worker note = _safe_string(note, 'note') 836*cda5da8dSAndroid Build Coastguard Worker yield from [l + '\n' for l in note.split('\n')] 837*cda5da8dSAndroid Build Coastguard Worker elif self.__notes__ is not None: 838*cda5da8dSAndroid Build Coastguard Worker yield _safe_string(self.__notes__, '__notes__', func=repr) 839*cda5da8dSAndroid Build Coastguard Worker 840*cda5da8dSAndroid Build Coastguard Worker def _format_syntax_error(self, stype): 841*cda5da8dSAndroid Build Coastguard Worker """Format SyntaxError exceptions (internal helper).""" 842*cda5da8dSAndroid Build Coastguard Worker # Show exactly where the problem was found. 843*cda5da8dSAndroid Build Coastguard Worker filename_suffix = '' 844*cda5da8dSAndroid Build Coastguard Worker if self.lineno is not None: 845*cda5da8dSAndroid Build Coastguard Worker yield ' File "{}", line {}\n'.format( 846*cda5da8dSAndroid Build Coastguard Worker self.filename or "<string>", self.lineno) 847*cda5da8dSAndroid Build Coastguard Worker elif self.filename is not None: 848*cda5da8dSAndroid Build Coastguard Worker filename_suffix = ' ({})'.format(self.filename) 849*cda5da8dSAndroid Build Coastguard Worker 850*cda5da8dSAndroid Build Coastguard Worker text = self.text 851*cda5da8dSAndroid Build Coastguard Worker if text is not None: 852*cda5da8dSAndroid Build Coastguard Worker # text = " foo\n" 853*cda5da8dSAndroid Build Coastguard Worker # rtext = " foo" 854*cda5da8dSAndroid Build Coastguard Worker # ltext = "foo" 855*cda5da8dSAndroid Build Coastguard Worker rtext = text.rstrip('\n') 856*cda5da8dSAndroid Build Coastguard Worker ltext = rtext.lstrip(' \n\f') 857*cda5da8dSAndroid Build Coastguard Worker spaces = len(rtext) - len(ltext) 858*cda5da8dSAndroid Build Coastguard Worker yield ' {}\n'.format(ltext) 859*cda5da8dSAndroid Build Coastguard Worker 860*cda5da8dSAndroid Build Coastguard Worker if self.offset is not None: 861*cda5da8dSAndroid Build Coastguard Worker offset = self.offset 862*cda5da8dSAndroid Build Coastguard Worker end_offset = self.end_offset if self.end_offset not in {None, 0} else offset 863*cda5da8dSAndroid Build Coastguard Worker if offset == end_offset or end_offset == -1: 864*cda5da8dSAndroid Build Coastguard Worker end_offset = offset + 1 865*cda5da8dSAndroid Build Coastguard Worker 866*cda5da8dSAndroid Build Coastguard Worker # Convert 1-based column offset to 0-based index into stripped text 867*cda5da8dSAndroid Build Coastguard Worker colno = offset - 1 - spaces 868*cda5da8dSAndroid Build Coastguard Worker end_colno = end_offset - 1 - spaces 869*cda5da8dSAndroid Build Coastguard Worker if colno >= 0: 870*cda5da8dSAndroid Build Coastguard Worker # non-space whitespace (likes tabs) must be kept for alignment 871*cda5da8dSAndroid Build Coastguard Worker caretspace = ((c if c.isspace() else ' ') for c in ltext[:colno]) 872*cda5da8dSAndroid Build Coastguard Worker yield ' {}{}'.format("".join(caretspace), ('^' * (end_colno - colno) + "\n")) 873*cda5da8dSAndroid Build Coastguard Worker msg = self.msg or "<no detail available>" 874*cda5da8dSAndroid Build Coastguard Worker yield "{}: {}{}\n".format(stype, msg, filename_suffix) 875*cda5da8dSAndroid Build Coastguard Worker 876*cda5da8dSAndroid Build Coastguard Worker def format(self, *, chain=True, _ctx=None): 877*cda5da8dSAndroid Build Coastguard Worker """Format the exception. 878*cda5da8dSAndroid Build Coastguard Worker 879*cda5da8dSAndroid Build Coastguard Worker If chain is not *True*, *__cause__* and *__context__* will not be formatted. 880*cda5da8dSAndroid Build Coastguard Worker 881*cda5da8dSAndroid Build Coastguard Worker The return value is a generator of strings, each ending in a newline and 882*cda5da8dSAndroid Build Coastguard Worker some containing internal newlines. `print_exception` is a wrapper around 883*cda5da8dSAndroid Build Coastguard Worker this method which just prints the lines to a file. 884*cda5da8dSAndroid Build Coastguard Worker 885*cda5da8dSAndroid Build Coastguard Worker The message indicating which exception occurred is always the last 886*cda5da8dSAndroid Build Coastguard Worker string in the output. 887*cda5da8dSAndroid Build Coastguard Worker """ 888*cda5da8dSAndroid Build Coastguard Worker 889*cda5da8dSAndroid Build Coastguard Worker if _ctx is None: 890*cda5da8dSAndroid Build Coastguard Worker _ctx = _ExceptionPrintContext() 891*cda5da8dSAndroid Build Coastguard Worker 892*cda5da8dSAndroid Build Coastguard Worker output = [] 893*cda5da8dSAndroid Build Coastguard Worker exc = self 894*cda5da8dSAndroid Build Coastguard Worker if chain: 895*cda5da8dSAndroid Build Coastguard Worker while exc: 896*cda5da8dSAndroid Build Coastguard Worker if exc.__cause__ is not None: 897*cda5da8dSAndroid Build Coastguard Worker chained_msg = _cause_message 898*cda5da8dSAndroid Build Coastguard Worker chained_exc = exc.__cause__ 899*cda5da8dSAndroid Build Coastguard Worker elif (exc.__context__ is not None and 900*cda5da8dSAndroid Build Coastguard Worker not exc.__suppress_context__): 901*cda5da8dSAndroid Build Coastguard Worker chained_msg = _context_message 902*cda5da8dSAndroid Build Coastguard Worker chained_exc = exc.__context__ 903*cda5da8dSAndroid Build Coastguard Worker else: 904*cda5da8dSAndroid Build Coastguard Worker chained_msg = None 905*cda5da8dSAndroid Build Coastguard Worker chained_exc = None 906*cda5da8dSAndroid Build Coastguard Worker 907*cda5da8dSAndroid Build Coastguard Worker output.append((chained_msg, exc)) 908*cda5da8dSAndroid Build Coastguard Worker exc = chained_exc 909*cda5da8dSAndroid Build Coastguard Worker else: 910*cda5da8dSAndroid Build Coastguard Worker output.append((None, exc)) 911*cda5da8dSAndroid Build Coastguard Worker 912*cda5da8dSAndroid Build Coastguard Worker for msg, exc in reversed(output): 913*cda5da8dSAndroid Build Coastguard Worker if msg is not None: 914*cda5da8dSAndroid Build Coastguard Worker yield from _ctx.emit(msg) 915*cda5da8dSAndroid Build Coastguard Worker if exc.exceptions is None: 916*cda5da8dSAndroid Build Coastguard Worker if exc.stack: 917*cda5da8dSAndroid Build Coastguard Worker yield from _ctx.emit('Traceback (most recent call last):\n') 918*cda5da8dSAndroid Build Coastguard Worker yield from _ctx.emit(exc.stack.format()) 919*cda5da8dSAndroid Build Coastguard Worker yield from _ctx.emit(exc.format_exception_only()) 920*cda5da8dSAndroid Build Coastguard Worker elif _ctx.exception_group_depth > self.max_group_depth: 921*cda5da8dSAndroid Build Coastguard Worker # exception group, but depth exceeds limit 922*cda5da8dSAndroid Build Coastguard Worker yield from _ctx.emit( 923*cda5da8dSAndroid Build Coastguard Worker f"... (max_group_depth is {self.max_group_depth})\n") 924*cda5da8dSAndroid Build Coastguard Worker else: 925*cda5da8dSAndroid Build Coastguard Worker # format exception group 926*cda5da8dSAndroid Build Coastguard Worker is_toplevel = (_ctx.exception_group_depth == 0) 927*cda5da8dSAndroid Build Coastguard Worker if is_toplevel: 928*cda5da8dSAndroid Build Coastguard Worker _ctx.exception_group_depth += 1 929*cda5da8dSAndroid Build Coastguard Worker 930*cda5da8dSAndroid Build Coastguard Worker if exc.stack: 931*cda5da8dSAndroid Build Coastguard Worker yield from _ctx.emit( 932*cda5da8dSAndroid Build Coastguard Worker 'Exception Group Traceback (most recent call last):\n', 933*cda5da8dSAndroid Build Coastguard Worker margin_char = '+' if is_toplevel else None) 934*cda5da8dSAndroid Build Coastguard Worker yield from _ctx.emit(exc.stack.format()) 935*cda5da8dSAndroid Build Coastguard Worker 936*cda5da8dSAndroid Build Coastguard Worker yield from _ctx.emit(exc.format_exception_only()) 937*cda5da8dSAndroid Build Coastguard Worker num_excs = len(exc.exceptions) 938*cda5da8dSAndroid Build Coastguard Worker if num_excs <= self.max_group_width: 939*cda5da8dSAndroid Build Coastguard Worker n = num_excs 940*cda5da8dSAndroid Build Coastguard Worker else: 941*cda5da8dSAndroid Build Coastguard Worker n = self.max_group_width + 1 942*cda5da8dSAndroid Build Coastguard Worker _ctx.need_close = False 943*cda5da8dSAndroid Build Coastguard Worker for i in range(n): 944*cda5da8dSAndroid Build Coastguard Worker last_exc = (i == n-1) 945*cda5da8dSAndroid Build Coastguard Worker if last_exc: 946*cda5da8dSAndroid Build Coastguard Worker # The closing frame may be added by a recursive call 947*cda5da8dSAndroid Build Coastguard Worker _ctx.need_close = True 948*cda5da8dSAndroid Build Coastguard Worker 949*cda5da8dSAndroid Build Coastguard Worker if self.max_group_width is not None: 950*cda5da8dSAndroid Build Coastguard Worker truncated = (i >= self.max_group_width) 951*cda5da8dSAndroid Build Coastguard Worker else: 952*cda5da8dSAndroid Build Coastguard Worker truncated = False 953*cda5da8dSAndroid Build Coastguard Worker title = f'{i+1}' if not truncated else '...' 954*cda5da8dSAndroid Build Coastguard Worker yield (_ctx.indent() + 955*cda5da8dSAndroid Build Coastguard Worker ('+-' if i==0 else ' ') + 956*cda5da8dSAndroid Build Coastguard Worker f'+---------------- {title} ----------------\n') 957*cda5da8dSAndroid Build Coastguard Worker _ctx.exception_group_depth += 1 958*cda5da8dSAndroid Build Coastguard Worker if not truncated: 959*cda5da8dSAndroid Build Coastguard Worker yield from exc.exceptions[i].format(chain=chain, _ctx=_ctx) 960*cda5da8dSAndroid Build Coastguard Worker else: 961*cda5da8dSAndroid Build Coastguard Worker remaining = num_excs - self.max_group_width 962*cda5da8dSAndroid Build Coastguard Worker plural = 's' if remaining > 1 else '' 963*cda5da8dSAndroid Build Coastguard Worker yield from _ctx.emit( 964*cda5da8dSAndroid Build Coastguard Worker f"and {remaining} more exception{plural}\n") 965*cda5da8dSAndroid Build Coastguard Worker 966*cda5da8dSAndroid Build Coastguard Worker if last_exc and _ctx.need_close: 967*cda5da8dSAndroid Build Coastguard Worker yield (_ctx.indent() + 968*cda5da8dSAndroid Build Coastguard Worker "+------------------------------------\n") 969*cda5da8dSAndroid Build Coastguard Worker _ctx.need_close = False 970*cda5da8dSAndroid Build Coastguard Worker _ctx.exception_group_depth -= 1 971*cda5da8dSAndroid Build Coastguard Worker 972*cda5da8dSAndroid Build Coastguard Worker if is_toplevel: 973*cda5da8dSAndroid Build Coastguard Worker assert _ctx.exception_group_depth == 1 974*cda5da8dSAndroid Build Coastguard Worker _ctx.exception_group_depth = 0 975*cda5da8dSAndroid Build Coastguard Worker 976*cda5da8dSAndroid Build Coastguard Worker 977*cda5da8dSAndroid Build Coastguard Worker def print(self, *, file=None, chain=True): 978*cda5da8dSAndroid Build Coastguard Worker """Print the result of self.format(chain=chain) to 'file'.""" 979*cda5da8dSAndroid Build Coastguard Worker if file is None: 980*cda5da8dSAndroid Build Coastguard Worker file = sys.stderr 981*cda5da8dSAndroid Build Coastguard Worker for line in self.format(chain=chain): 982*cda5da8dSAndroid Build Coastguard Worker print(line, file=file, end="") 983