Skip to content

Commit 6202ef6

Browse files
committed
gh-140456: Clarify traceback source line documentation
1 parent 1b41c7b commit 6202ef6

3 files changed

Lines changed: 37 additions & 7 deletions

File tree

Doc/library/traceback.rst

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,10 @@ Module-Level Functions
172172
:func:`extract_tb` or :func:`extract_stack`, return a list of strings ready
173173
for printing. Each string in the resulting list corresponds to the item with
174174
the same index in the argument list. Each string ends in a newline; the
175-
strings may contain internal newlines as well, for those items whose source
176-
text line is not ``None``.
175+
strings may contain internal newlines as well, for items whose source text
176+
spans multiple physical lines and has column position information. When
177+
column position information is unavailable, only the first physical line is
178+
displayed. Old-style tuples never have column position information.
177179

178180

179181
.. function:: format_exception_only(exc, /[, value], *, show_group=False)
@@ -471,6 +473,10 @@ the module-level functions described above.
471473
:class:`FrameSummary` objects or old-style list of tuples. Each tuple
472474
should be a 4-tuple with *filename*, *lineno*, *name*, *line* as the
473475
elements.
476+
Old-style tuples do not have column position information, so only the
477+
first physical line of *line* is displayed when they are formatted. The
478+
same applies to :class:`FrameSummary` objects without column position
479+
information.
474480

475481
.. method:: format()
476482

@@ -540,7 +546,7 @@ in a :ref:`traceback <traceback-objects>`.
540546

541547
.. attribute:: FrameSummary.line
542548

543-
A string representing the source code for this frame, with leading and
549+
The first physical line of source code for this frame, with leading and
544550
trailing whitespace stripped.
545551
If the source is not available, it is ``None``.
546552

Lib/test/test_traceback.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3354,6 +3354,10 @@ def test_explicit_line(self):
33543354
f = traceback.FrameSummary("f", 1, "dummy", line="line")
33553355
self.assertEqual("line", f.line)
33563356

3357+
def test_explicit_multiline_line(self):
3358+
f = traceback.FrameSummary("f", 1, "dummy", line="line 1\nline 2")
3359+
self.assertEqual("line 1", f.line)
3360+
33573361
def test_len(self):
33583362
f = traceback.FrameSummary("f", 1, "dummy", line="line")
33593363
self.assertEqual(len(f), 4)
@@ -3415,6 +3419,18 @@ def test_from_list(self):
34153419
[' File "foo.py", line 1, in fred\n line\n'],
34163420
s.format())
34173421

3422+
def test_from_list_multiline_without_columns(self):
3423+
for frame in [
3424+
('foo.py', 1, 'fred', 'line 1\nline 2'),
3425+
traceback.FrameSummary(
3426+
'foo.py', 1, 'fred', line='line 1\nline 2'),
3427+
]:
3428+
with self.subTest(frame=frame):
3429+
s = traceback.StackSummary.from_list([frame])
3430+
self.assertEqual(
3431+
[' File "foo.py", line 1, in fred\n line 1\n'],
3432+
s.format())
3433+
34183434
def test_from_list_edited_stack(self):
34193435
s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
34203436
s[0] = ('foo.py', 2, 'fred', 'line')

Lib/traceback.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,11 @@ def format_list(extracted_list):
8484
8585
Each string in the resulting list corresponds to the item with the
8686
same index in the argument list. Each string ends in a newline;
87-
the strings may contain internal newlines as well, for those items
88-
whose source text line is not None.
87+
the strings may contain internal newlines as well, for items whose
88+
source text spans multiple physical lines and has column position
89+
information. When column position information is unavailable, only
90+
the first physical line is displayed. Old-style tuples never have
91+
column position information.
8992
"""
9093
return StackSummary.from_list(extracted_list).format()
9194

@@ -324,8 +327,8 @@ class FrameSummary:
324327
active when the frame was captured.
325328
- :attr:`name` The name of the function or method that was executing
326329
when the frame was captured.
327-
- :attr:`line` The text from the linecache module for the line
328-
of code that was running when the frame was captured.
330+
- :attr:`line` The first physical line of code that was running when
331+
the frame was captured.
329332
- :attr:`locals` Either None if locals were not supplied, or a dict
330333
mapping the name to the repr() of the variable.
331334
- :attr:`end_lineno` The last line number of the source code for this frame.
@@ -558,6 +561,11 @@ def from_list(klass, a_list):
558561
"""
559562
Create a StackSummary object from a supplied list of
560563
FrameSummary objects or old-style list of tuples.
564+
565+
Old-style tuples do not have column position information, so only the
566+
first physical line of the line element is displayed when they are
567+
formatted. The same applies to FrameSummary objects without column
568+
position information.
561569
"""
562570
# While doing a fast-path check for isinstance(a_list, StackSummary) is
563571
# appealing, idlelib.run.cleanup_traceback and other similar code may

0 commit comments

Comments
 (0)