1"""Extract, format and print information about Python stack traces.""" 2 3import collections 4import itertools 5import linecache 6import sys 7 8__all__ = ['extract_stack', 'extract_tb', 'format_exception', 9 'format_exception_only', 'format_list', 'format_stack', 10 'format_tb', 'print_exc', 'format_exc', 'print_exception', 11 'print_last', 'print_stack', 'print_tb', 'clear_frames', 12 'FrameSummary', 'StackSummary', 'TracebackException', 13 'walk_stack', 'walk_tb'] 14 15# 16# Formatting and printing lists of traceback lines. 17# 18 19def print_list(extracted_list, file=None): 20 """Print the list of tuples as returned by extract_tb() or 21 extract_stack() as a formatted stack trace to the given file.""" 22 if file is None: 23 file = sys.stderr 24 for item in StackSummary.from_list(extracted_list).format(): 25 print(item, file=file, end="") 26 27def format_list(extracted_list): 28 """Format a list of traceback entry tuples for printing. 29 30 Given a list of tuples as returned by extract_tb() or 31 extract_stack(), return a list of strings ready for printing. 32 Each string in the resulting list corresponds to the item with the 33 same index in the argument list. Each string ends in a newline; 34 the strings may contain internal newlines as well, for those items 35 whose source text line is not None. 36 """ 37 return StackSummary.from_list(extracted_list).format() 38 39# 40# Printing and Extracting Tracebacks. 41# 42 43def print_tb(tb, limit=None, file=None): 44 """Print up to 'limit' stack trace entries from the traceback 'tb'. 45 46 If 'limit' is omitted or None, all entries are printed. If 'file' 47 is omitted or None, the output goes to sys.stderr; otherwise 48 'file' should be an open file or file-like object with a write() 49 method. 50 """ 51 print_list(extract_tb(tb, limit=limit), file=file) 52 53def format_tb(tb, limit=None): 54 """A shorthand for 'format_list(extract_tb(tb, limit))'.""" 55 return extract_tb(tb, limit=limit).format() 56 57def extract_tb(tb, limit=None): 58 """Return list of up to limit pre-processed entries from traceback. 59 60 This is useful for alternate formatting of stack traces. If 61 'limit' is omitted or None, all entries are extracted. A 62 pre-processed stack trace entry is a quadruple (filename, line 63 number, function name, text) representing the information that is 64 usually printed for a stack trace. The text is a string with 65 leading and trailing whitespace stripped; if the source is not 66 available it is None. 67 """ 68 return StackSummary.extract(walk_tb(tb), limit=limit) 69 70# 71# Exception formatting and output. 72# 73 74_cause_message = ( 75 "\nThe above exception was the direct cause " 76 "of the following exception:\n\n") 77 78_context_message = ( 79 "\nDuring handling of the above exception, " 80 "another exception occurred:\n\n") 81 82 83def print_exception(etype, value, tb, limit=None, file=None, chain=True): 84 """Print exception up to 'limit' stack trace entries from 'tb' to 'file'. 85 86 This differs from print_tb() in the following ways: (1) if 87 traceback is not None, it prints a header "Traceback (most recent 88 call last):"; (2) it prints the exception type and value after the 89 stack trace; (3) if type is SyntaxError and value has the 90 appropriate format, it prints the line where the syntax error 91 occurred with a caret on the next line indicating the approximate 92 position of the error. 93 """ 94 # format_exception has ignored etype for some time, and code such as cgitb 95 # passes in bogus values as a result. For compatibility with such code we 96 # ignore it here (rather than in the new TracebackException API). 97 if file is None: 98 file = sys.stderr 99 for line in TracebackException( 100 type(value), value, tb, limit=limit).format(chain=chain): 101 print(line, file=file, end="") 102 103 104def format_exception(etype, value, tb, limit=None, chain=True): 105 """Format a stack trace and the exception information. 106 107 The arguments have the same meaning as the corresponding arguments 108 to print_exception(). The return value is a list of strings, each 109 ending in a newline and some containing internal newlines. When 110 these lines are concatenated and printed, exactly the same text is 111 printed as does print_exception(). 112 """ 113 # format_exception has ignored etype for some time, and code such as cgitb 114 # passes in bogus values as a result. For compatibility with such code we 115 # ignore it here (rather than in the new TracebackException API). 116 return list(TracebackException( 117 type(value), value, tb, limit=limit).format(chain=chain)) 118 119 120def format_exception_only(etype, value): 121 """Format the exception part of a traceback. 122 123 The arguments are the exception type and value such as given by 124 sys.last_type and sys.last_value. The return value is a list of 125 strings, each ending in a newline. 126 127 Normally, the list contains a single string; however, for 128 SyntaxError exceptions, it contains several lines that (when 129 printed) display detailed information about where the syntax 130 error occurred. 131 132 The message indicating which exception occurred is always the last 133 string in the list. 134 135 """ 136 return list(TracebackException(etype, value, None).format_exception_only()) 137 138 139# -- not official API but folk probably use these two functions. 140 141def _format_final_exc_line(etype, value): 142 valuestr = _some_str(value) 143 if value is None or not valuestr: 144 line = "%s\n" % etype 145 else: 146 line = "%s: %s\n" % (etype, valuestr) 147 return line 148 149def _some_str(value): 150 try: 151 return str(value) 152 except: 153 return '<unprintable %s object>' % type(value).__name__ 154 155# -- 156 157def print_exc(limit=None, file=None, chain=True): 158 """Shorthand for 'print_exception(*sys.exc_info(), limit, file)'.""" 159 print_exception(*sys.exc_info(), limit=limit, file=file, chain=chain) 160 161def format_exc(limit=None, chain=True): 162 """Like print_exc() but return a string.""" 163 return "".join(format_exception(*sys.exc_info(), limit=limit, chain=chain)) 164 165def print_last(limit=None, file=None, chain=True): 166 """This is a shorthand for 'print_exception(sys.last_type, 167 sys.last_value, sys.last_traceback, limit, file)'.""" 168 if not hasattr(sys, "last_type"): 169 raise ValueError("no last exception") 170 print_exception(sys.last_type, sys.last_value, sys.last_traceback, 171 limit, file, chain) 172 173# 174# Printing and Extracting Stacks. 175# 176 177def print_stack(f=None, limit=None, file=None): 178 """Print a stack trace from its invocation point. 179 180 The optional 'f' argument can be used to specify an alternate 181 stack frame at which to start. The optional 'limit' and 'file' 182 arguments have the same meaning as for print_exception(). 183 """ 184 if f is None: 185 f = sys._getframe().f_back 186 print_list(extract_stack(f, limit=limit), file=file) 187 188 189def format_stack(f=None, limit=None): 190 """Shorthand for 'format_list(extract_stack(f, limit))'.""" 191 if f is None: 192 f = sys._getframe().f_back 193 return format_list(extract_stack(f, limit=limit)) 194 195 196def extract_stack(f=None, limit=None): 197 """Extract the raw traceback from the current stack frame. 198 199 The return value has the same format as for extract_tb(). The 200 optional 'f' and 'limit' arguments have the same meaning as for 201 print_stack(). Each item in the list is a quadruple (filename, 202 line number, function name, text), and the entries are in order 203 from oldest to newest stack frame. 204 """ 205 if f is None: 206 f = sys._getframe().f_back 207 stack = StackSummary.extract(walk_stack(f), limit=limit) 208 stack.reverse() 209 return stack 210 211 212def clear_frames(tb): 213 "Clear all references to local variables in the frames of a traceback." 214 while tb is not None: 215 try: 216 tb.tb_frame.clear() 217 except RuntimeError: 218 # Ignore the exception raised if the frame is still executing. 219 pass 220 tb = tb.tb_next 221 222 223class FrameSummary: 224 """A single frame from a traceback. 225 226 - :attr:`filename` The filename for the frame. 227 - :attr:`lineno` The line within filename for the frame that was 228 active when the frame was captured. 229 - :attr:`name` The name of the function or method that was executing 230 when the frame was captured. 231 - :attr:`line` The text from the linecache module for the 232 of code that was running when the frame was captured. 233 - :attr:`locals` Either None if locals were not supplied, or a dict 234 mapping the name to the repr() of the variable. 235 """ 236 237 __slots__ = ('filename', 'lineno', 'name', '_line', 'locals') 238 239 def __init__(self, filename, lineno, name, *, lookup_line=True, 240 locals=None, line=None): 241 """Construct a FrameSummary. 242 243 :param lookup_line: If True, `linecache` is consulted for the source 244 code line. Otherwise, the line will be looked up when first needed. 245 :param locals: If supplied the frame locals, which will be captured as 246 object representations. 247 :param line: If provided, use this instead of looking up the line in 248 the linecache. 249 """ 250 self.filename = filename 251 self.lineno = lineno 252 self.name = name 253 self._line = line 254 if lookup_line: 255 self.line 256 self.locals = \ 257 dict((k, repr(v)) for k, v in locals.items()) if locals else None 258 259 def __eq__(self, other): 260 if isinstance(other, FrameSummary): 261 return (self.filename == other.filename and 262 self.lineno == other.lineno and 263 self.name == other.name and 264 self.locals == other.locals) 265 if isinstance(other, tuple): 266 return (self.filename, self.lineno, self.name, self.line) == other 267 return NotImplemented 268 269 def __getitem__(self, pos): 270 return (self.filename, self.lineno, self.name, self.line)[pos] 271 272 def __iter__(self): 273 return iter([self.filename, self.lineno, self.name, self.line]) 274 275 def __repr__(self): 276 return "<FrameSummary file {filename}, line {lineno} in {name}>".format( 277 filename=self.filename, lineno=self.lineno, name=self.name) 278 279 @property 280 def line(self): 281 if self._line is None: 282 self._line = linecache.getline(self.filename, self.lineno).strip() 283 return self._line 284 285 286def walk_stack(f): 287 """Walk a stack yielding the frame and line number for each frame. 288 289 This will follow f.f_back from the given frame. If no frame is given, the 290 current stack is used. Usually used with StackSummary.extract. 291 """ 292 if f is None: 293 f = sys._getframe().f_back.f_back 294 while f is not None: 295 yield f, f.f_lineno 296 f = f.f_back 297 298 299def walk_tb(tb): 300 """Walk a traceback yielding the frame and line number for each frame. 301 302 This will follow tb.tb_next (and thus is in the opposite order to 303 walk_stack). Usually used with StackSummary.extract. 304 """ 305 while tb is not None: 306 yield tb.tb_frame, tb.tb_lineno 307 tb = tb.tb_next 308 309 310class StackSummary(list): 311 """A stack of frames.""" 312 313 @classmethod 314 def extract(klass, frame_gen, *, limit=None, lookup_lines=True, 315 capture_locals=False): 316 """Create a StackSummary from a traceback or stack object. 317 318 :param frame_gen: A generator that yields (frame, lineno) tuples to 319 include in the stack. 320 :param limit: None to include all frames or the number of frames to 321 include. 322 :param lookup_lines: If True, lookup lines for each frame immediately, 323 otherwise lookup is deferred until the frame is rendered. 324 :param capture_locals: If True, the local variables from each frame will 325 be captured as object representations into the FrameSummary. 326 """ 327 if limit is None: 328 limit = getattr(sys, 'tracebacklimit', None) 329 if limit is not None and limit < 0: 330 limit = 0 331 if limit is not None: 332 if limit >= 0: 333 frame_gen = itertools.islice(frame_gen, limit) 334 else: 335 frame_gen = collections.deque(frame_gen, maxlen=-limit) 336 337 result = klass() 338 fnames = set() 339 for f, lineno in frame_gen: 340 co = f.f_code 341 filename = co.co_filename 342 name = co.co_name 343 344 fnames.add(filename) 345 linecache.lazycache(filename, f.f_globals) 346 # Must defer line lookups until we have called checkcache. 347 if capture_locals: 348 f_locals = f.f_locals 349 else: 350 f_locals = None 351 result.append(FrameSummary( 352 filename, lineno, name, lookup_line=False, locals=f_locals)) 353 for filename in fnames: 354 linecache.checkcache(filename) 355 # If immediate lookup was desired, trigger lookups now. 356 if lookup_lines: 357 for f in result: 358 f.line 359 return result 360 361 @classmethod 362 def from_list(klass, a_list): 363 """Create a StackSummary from a simple list of tuples. 364 365 This method supports the older Python API. Each tuple should be a 366 4-tuple with (filename, lineno, name, line) elements. 367 """ 368 # While doing a fast-path check for isinstance(a_list, StackSummary) is 369 # appealing, idlelib.run.cleanup_traceback and other similar code may 370 # break this by making arbitrary frames plain tuples, so we need to 371 # check on a frame by frame basis. 372 result = StackSummary() 373 for frame in a_list: 374 if isinstance(frame, FrameSummary): 375 result.append(frame) 376 else: 377 filename, lineno, name, line = frame 378 result.append(FrameSummary(filename, lineno, name, line=line)) 379 return result 380 381 def format(self): 382 """Format the stack ready for printing. 383 384 Returns a list of strings ready for printing. Each string in the 385 resulting list corresponds to a single frame from the stack. 386 Each string ends in a newline; the strings may contain internal 387 newlines as well, for those items with source text lines. 388 389 For long sequences of the same frame and line, the first few 390 repetitions are shown, followed by a summary line stating the exact 391 number of further repetitions. 392 """ 393 result = [] 394 last_file = None 395 last_line = None 396 last_name = None 397 count = 0 398 for frame in self: 399 if (last_file is not None and last_file == frame.filename and 400 last_line is not None and last_line == frame.lineno and 401 last_name is not None and last_name == frame.name): 402 count += 1 403 else: 404 if count > 3: 405 result.append(f' [Previous line repeated {count-3} more times]\n') 406 last_file = frame.filename 407 last_line = frame.lineno 408 last_name = frame.name 409 count = 0 410 if count >= 3: 411 continue 412 row = [] 413 row.append(' File "{}", line {}, in {}\n'.format( 414 frame.filename, frame.lineno, frame.name)) 415 if frame.line: 416 row.append(' {}\n'.format(frame.line.strip())) 417 if frame.locals: 418 for name, value in sorted(frame.locals.items()): 419 row.append(' {name} = {value}\n'.format(name=name, value=value)) 420 result.append(''.join(row)) 421 if count > 3: 422 result.append(f' [Previous line repeated {count-3} more times]\n') 423 return result 424 425 426class TracebackException: 427 """An exception ready for rendering. 428 429 The traceback module captures enough attributes from the original exception 430 to this intermediary form to ensure that no references are held, while 431 still being able to fully print or format it. 432 433 Use `from_exception` to create TracebackException instances from exception 434 objects, or the constructor to create TracebackException instances from 435 individual components. 436 437 - :attr:`__cause__` A TracebackException of the original *__cause__*. 438 - :attr:`__context__` A TracebackException of the original *__context__*. 439 - :attr:`__suppress_context__` The *__suppress_context__* value from the 440 original exception. 441 - :attr:`stack` A `StackSummary` representing the traceback. 442 - :attr:`exc_type` The class of the original traceback. 443 - :attr:`filename` For syntax errors - the filename where the error 444 occurred. 445 - :attr:`lineno` For syntax errors - the linenumber where the error 446 occurred. 447 - :attr:`text` For syntax errors - the text where the error 448 occurred. 449 - :attr:`offset` For syntax errors - the offset into the text where the 450 error occurred. 451 - :attr:`msg` For syntax errors - the compiler error message. 452 """ 453 454 def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, 455 lookup_lines=True, capture_locals=False, _seen=None): 456 # NB: we need to accept exc_traceback, exc_value, exc_traceback to 457 # permit backwards compat with the existing API, otherwise we 458 # need stub thunk objects just to glue it together. 459 # Handle loops in __cause__ or __context__. 460 if _seen is None: 461 _seen = set() 462 _seen.add(exc_value) 463 # Gracefully handle (the way Python 2.4 and earlier did) the case of 464 # being called with no type or value (None, None, None). 465 if (exc_value and exc_value.__cause__ is not None 466 and exc_value.__cause__ not in _seen): 467 cause = TracebackException( 468 type(exc_value.__cause__), 469 exc_value.__cause__, 470 exc_value.__cause__.__traceback__, 471 limit=limit, 472 lookup_lines=False, 473 capture_locals=capture_locals, 474 _seen=_seen) 475 else: 476 cause = None 477 if (exc_value and exc_value.__context__ is not None 478 and exc_value.__context__ not in _seen): 479 context = TracebackException( 480 type(exc_value.__context__), 481 exc_value.__context__, 482 exc_value.__context__.__traceback__, 483 limit=limit, 484 lookup_lines=False, 485 capture_locals=capture_locals, 486 _seen=_seen) 487 else: 488 context = None 489 self.exc_traceback = exc_traceback 490 self.__cause__ = cause 491 self.__context__ = context 492 self.__suppress_context__ = \ 493 exc_value.__suppress_context__ if exc_value else False 494 # TODO: locals. 495 self.stack = StackSummary.extract( 496 walk_tb(exc_traceback), limit=limit, lookup_lines=lookup_lines, 497 capture_locals=capture_locals) 498 self.exc_type = exc_type 499 # Capture now to permit freeing resources: only complication is in the 500 # unofficial API _format_final_exc_line 501 self._str = _some_str(exc_value) 502 if exc_type and issubclass(exc_type, SyntaxError): 503 # Handle SyntaxError's specially 504 self.filename = exc_value.filename 505 self.lineno = str(exc_value.lineno) 506 self.text = exc_value.text 507 self.offset = exc_value.offset 508 self.msg = exc_value.msg 509 if lookup_lines: 510 self._load_lines() 511 512 @classmethod 513 def from_exception(cls, exc, *args, **kwargs): 514 """Create a TracebackException from an exception.""" 515 return cls(type(exc), exc, exc.__traceback__, *args, **kwargs) 516 517 def _load_lines(self): 518 """Private API. force all lines in the stack to be loaded.""" 519 for frame in self.stack: 520 frame.line 521 if self.__context__: 522 self.__context__._load_lines() 523 if self.__cause__: 524 self.__cause__._load_lines() 525 526 def __eq__(self, other): 527 return self.__dict__ == other.__dict__ 528 529 def __str__(self): 530 return self._str 531 532 def format_exception_only(self): 533 """Format the exception part of the traceback. 534 535 The return value is a generator of strings, each ending in a newline. 536 537 Normally, the generator emits a single string; however, for 538 SyntaxError exceptions, it emites several lines that (when 539 printed) display detailed information about where the syntax 540 error occurred. 541 542 The message indicating which exception occurred is always the last 543 string in the output. 544 """ 545 if self.exc_type is None: 546 yield _format_final_exc_line(None, self._str) 547 return 548 549 stype = self.exc_type.__qualname__ 550 smod = self.exc_type.__module__ 551 if smod not in ("__main__", "builtins"): 552 stype = smod + '.' + stype 553 554 if not issubclass(self.exc_type, SyntaxError): 555 yield _format_final_exc_line(stype, self._str) 556 return 557 558 # It was a syntax error; show exactly where the problem was found. 559 filename = self.filename or "<string>" 560 lineno = str(self.lineno) or '?' 561 yield ' File "{}", line {}\n'.format(filename, lineno) 562 563 badline = self.text 564 offset = self.offset 565 if badline is not None: 566 yield ' {}\n'.format(badline.strip()) 567 if offset is not None: 568 caretspace = badline.rstrip('\n') 569 offset = min(len(caretspace), offset) - 1 570 caretspace = caretspace[:offset].lstrip() 571 # non-space whitespace (likes tabs) must be kept for alignment 572 caretspace = ((c.isspace() and c or ' ') for c in caretspace) 573 yield ' {}^\n'.format(''.join(caretspace)) 574 msg = self.msg or "<no detail available>" 575 yield "{}: {}\n".format(stype, msg) 576 577 def format(self, *, chain=True): 578 """Format the exception. 579 580 If chain is not *True*, *__cause__* and *__context__* will not be formatted. 581 582 The return value is a generator of strings, each ending in a newline and 583 some containing internal newlines. `print_exception` is a wrapper around 584 this method which just prints the lines to a file. 585 586 The message indicating which exception occurred is always the last 587 string in the output. 588 """ 589 if chain: 590 if self.__cause__ is not None: 591 yield from self.__cause__.format(chain=chain) 592 yield _cause_message 593 elif (self.__context__ is not None and 594 not self.__suppress_context__): 595 yield from self.__context__.format(chain=chain) 596 yield _context_message 597 if self.exc_traceback is not None: 598 yield 'Traceback (most recent call last):\n' 599 yield from self.stack.format() 600 yield from self.format_exception_only() 601