A list of FrameSummary objects, representing a stack of frames.
| 448 | |
| 449 | |
| 450 | class StackSummary(list): |
| 451 | """A list of FrameSummary objects, representing a stack of frames.""" |
| 452 | |
| 453 | @classmethod |
| 454 | def extract(klass, frame_gen, *, limit=None, lookup_lines=True, |
| 455 | capture_locals=False): |
| 456 | """Create a StackSummary from a traceback or stack object. |
| 457 | |
| 458 | :param frame_gen: A generator that yields (frame, lineno) tuples |
| 459 | whose summaries are to be included in the stack. |
| 460 | :param limit: None to include all frames or the number of frames to |
| 461 | include. |
| 462 | :param lookup_lines: If True, lookup lines for each frame immediately, |
| 463 | otherwise lookup is deferred until the frame is rendered. |
| 464 | :param capture_locals: If True, the local variables from each frame will |
| 465 | be captured as object representations into the FrameSummary. |
| 466 | """ |
| 467 | def extended_frame_gen(): |
| 468 | for f, lineno in frame_gen: |
| 469 | yield f, (lineno, None, None, None) |
| 470 | |
| 471 | return klass._extract_from_extended_frame_gen( |
| 472 | extended_frame_gen(), limit=limit, lookup_lines=lookup_lines, |
| 473 | capture_locals=capture_locals) |
| 474 | |
| 475 | @classmethod |
| 476 | def _extract_from_extended_frame_gen(klass, frame_gen, *, limit=None, |
| 477 | lookup_lines=True, capture_locals=False): |
| 478 | # Same as extract but operates on a frame generator that yields |
| 479 | # (frame, (lineno, end_lineno, colno, end_colno)) in the stack. |
| 480 | # Only lineno is required, the remaining fields can be None if the |
| 481 | # information is not available. |
| 482 | builtin_limit = limit is BUILTIN_EXCEPTION_LIMIT |
| 483 | if limit is None or builtin_limit: |
| 484 | limit = getattr(sys, 'tracebacklimit', None) |
| 485 | if limit is not None and limit < 0: |
| 486 | limit = 0 |
| 487 | if limit is not None: |
| 488 | if builtin_limit: |
| 489 | frame_gen = tuple(frame_gen) |
| 490 | frame_gen = frame_gen[len(frame_gen) - limit:] |
| 491 | elif limit >= 0: |
| 492 | frame_gen = itertools.islice(frame_gen, limit) |
| 493 | else: |
| 494 | frame_gen = collections.deque(frame_gen, maxlen=-limit) |
| 495 | |
| 496 | result = klass() |
| 497 | fnames = set() |
| 498 | for f, (lineno, end_lineno, colno, end_colno) in frame_gen: |
| 499 | co = f.f_code |
| 500 | filename = co.co_filename |
| 501 | name = co.co_name |
| 502 | fnames.add(filename) |
| 503 | linecache.lazycache(filename, f.f_globals) |
| 504 | # Must defer line lookups until we have called checkcache. |
| 505 | if capture_locals: |
| 506 | f_locals = f.f_locals |
| 507 | else: |
no outgoing calls
no test coverage detected
searching dependent graphs…