Skip to main content

Lib/traceback.py

The traceback module is the public face of CPython's exception-printing pipeline. Every unhandled exception you see in a terminal passes through this file. In 3.14 the module grew colorization support via _colorize, extended position metadata (end-line, column, end-column), and a show_group path for BaseExceptionGroup trees.

Map

LinesSymbolRole
29-35print_listWrites a formatted stack list to a file, delegates to StackSummary.from_list
37-49format_listReturns a list of formatted strings from a StackSummary or legacy tuples
55-63print_tbPrints up to limit frames from a traceback object
65-67format_tbOne-liner wrapper: format_list(extract_tb(...))
69-83extract_tbBuilds a StackSummary from _walk_tb_with_full_positions
119-134print_exceptionTop-level print entry point, constructs TracebackException and calls .print()
146-159format_exceptionSame as print_exception but returns a list of strings
208-214print_exc / format_excConvenience wrappers around sys.exception()
278-379FrameSummaryHolds per-frame metadata: filename, lineno, end_lineno, colno, end_colno, name, locals
382-396walk_stackGenerator that walks f.f_back upward, yields (frame, lineno)
399-407walk_tbGenerator that walks tb.tb_next, yields (frame, lineno)
410-421_walk_tb_with_full_positionsInternal variant of walk_tb that yields 4-tuple positions from co_positions()
434-791StackSummarylist subclass; extract, from_list, format, format_frame_summary
459-507StackSummary._extract_from_extended_frame_genCore extractor, applies tracebacklimit, defers line lookups
528-710StackSummary.format_frame_summaryRenders one frame with caret underlining, colorization, and wide-char support
799-810_AnchorsNamed tuple recording binary-op / bracket anchor positions for caret rendering
812-956_extract_caret_anchors_from_line_segmentParses a code segment with ast to find op/subscript/call bracket positions
1004-1576TracebackExceptionSnapshot class: captures exc type, str, notes, syntax-error fields, chain, and groups
1044-1189TracebackException.__init__Walks __cause__ / __context__ iteratively to avoid recursion, captures StackSummary
1226-1278TracebackException.format_exception_onlyYields the final "ExcType: msg" line plus __notes__ and group children
1468-1566TracebackException.formatMain generator: resolves chain order, delegates to stack.format and format_exception_only
1602-1684_compute_suggestion_errorLevenshtein-based "Did you mean?" hint for NameError / AttributeError / ImportError
1687-1745_levenshtein_distancePure-Python port of Python/suggestions.c:levenshtein_distance

Reading

FrameSummary: capturing position metadata

FrameSummary stores everything needed to reconstruct one line of the "File ..., line N, in func" output. In 3.14 it gained end_lineno, colno, and end_colno from co_positions() so that multi-line expressions can be underlined precisely.

# CPython: Lib/traceback.py:292 FrameSummary.__slots__
__slots__ = ('filename', 'lineno', 'end_lineno', 'colno', 'end_colno',
'name', '_lines', '_lines_dedented', 'locals', '_code')

# CPython: Lib/traceback.py:359 FrameSummary._original_lines (property)
@property
def _original_lines(self):
self._set_lines()
return self._lines

# CPython: Lib/traceback.py:373 FrameSummary.line (property)
@property
def line(self):
self._set_lines()
if self._lines is None:
return None
return self._lines.partition("\n")[0].strip()

StackSummary.extract and the extended frame generator

extract is the public API; it wraps the frame generator to add None position fields and forwards to _extract_from_extended_frame_gen, which is also called directly by extract_tb with the full 4-tuple positions.

# CPython: Lib/traceback.py:438 StackSummary.extract
@classmethod
def extract(klass, frame_gen, *, limit=None, lookup_lines=True,
capture_locals=False):
def extended_frame_gen():
for f, lineno in frame_gen:
yield f, (lineno, None, None, None)
return klass._extract_from_extended_frame_gen(
extended_frame_gen(), limit=limit, lookup_lines=lookup_lines,
capture_locals=capture_locals)

# CPython: Lib/traceback.py:466 StackSummary._extract_from_extended_frame_gen (limit handling)
builtin_limit = limit is BUILTIN_EXCEPTION_LIMIT
if limit is None or builtin_limit:
limit = getattr(sys, 'tracebacklimit', None)
if limit is not None and limit < 0:
limit = 0

TracebackException: iterative chain walk

The constructor avoids Python recursion on deeply-chained exceptions by using an explicit queue. The _seen set (keyed by id(exc_value)) breaks __cause__ / __context__ cycles.

# CPython: Lib/traceback.py:1123 TracebackException.__init__ (queue loop)
if not is_recursive_call:
queue = [(self, exc_value)]
while queue:
te, e = queue.pop()
if (e is not None and e.__cause__ is not None
and id(e.__cause__) not in _seen):
cause = TracebackException(
type(e.__cause__), e.__cause__,
e.__cause__.__traceback__, ...)
else:
cause = None
...
te.__cause__ = cause
te.__context__ = context
te.exceptions = exceptions
if cause:
queue.append((te.__cause__, e.__cause__))

format_exc and print_exc convenience wrappers

Both wrappers call sys.exception() to retrieve the current exception from the interpreter thread state, which replaced the old three-argument sys.exc_info() pattern in 3.12.

# CPython: Lib/traceback.py:208 print_exc
def print_exc(limit=None, file=None, chain=True):
print_exception(sys.exception(), limit=limit, file=file, chain=chain)

# CPython: Lib/traceback.py:212 format_exc
def format_exc(limit=None, chain=True):
return "".join(format_exception(sys.exception(), limit=limit, chain=chain))

gopy notes

FrameSummary maps cleanly to a Go struct with pointer-nullable int fields for the column positions. The lazy _set_lines / line property pattern should become a sync.Once-guarded call to linecache.GetLine. StackSummary.format can stay as a method on []FrameSummary that returns []string.

TracebackException is the harder target: the iterative __cause__ / __context__ queue in __init__ must be reproduced exactly to avoid Go stack overflows on deep chains. The _Anchors AST walk (_extract_caret_anchors_from_line_segment) depends on a Python ast parse, which gopy does not yet expose; caret rendering can be stubbed to plain underlines until that gate is cleared.

_levenshtein_distance at lines 1687-1745 is a self-contained algorithm with no CPython-internal dependencies and is a straightforward port.