Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions Doc/library/traceback.rst
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,12 @@ Module-Level Functions
Given a list of tuples or :class:`FrameSummary` objects as returned by
:func:`extract_tb` or :func:`extract_stack`, return a list of strings ready
for printing. Each string in the resulting list corresponds to the item with
the same index in the argument list. Each string ends in a newline; the
strings may contain internal newlines as well, for those items whose source
text line is not ``None``.
the same index in the argument list. Each string ends in a newline and may
contain internal newlines. When an item's source text spans multiple
physical lines, every line is displayed only if the item has both column
position information and an end line number greater than its line number;
otherwise just the first physical line is displayed. Old-style tuples never
have column position information.


.. function:: format_exception_only(exc, /[, value], *, show_group=False)
Expand Down Expand Up @@ -471,14 +474,21 @@ the module-level functions described above.
:class:`FrameSummary` objects or old-style list of tuples. Each tuple
should be a 4-tuple with *filename*, *lineno*, *name*, *line* as the
elements.
Old-style tuples do not have column position information, so only the
first physical line of *line* is displayed when they are formatted. The
same applies to :class:`FrameSummary` objects without column position
information.

.. method:: format()

Returns a list of strings ready for printing. Each string in the
resulting list corresponds to a single :ref:`frame <frame-objects>` from
the stack.
Each string ends in a newline; the strings may contain internal
newlines as well, for those items with source text lines.
Each string ends in a newline and may contain internal newlines. When a
frame's source text spans multiple physical lines, every line is displayed
only if the frame has both column position information and an end line
number greater than its line number; otherwise just the first physical
line is displayed.

For long sequences of the same frame and line, the first few
repetitions are shown, followed by a summary line stating the exact
Expand Down Expand Up @@ -540,7 +550,7 @@ in a :ref:`traceback <traceback-objects>`.

.. attribute:: FrameSummary.line

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

Expand Down
44 changes: 44 additions & 0 deletions Lib/test/test_traceback.py
Original file line number Diff line number Diff line change
Expand Up @@ -3354,6 +3354,10 @@ def test_explicit_line(self):
f = traceback.FrameSummary("f", 1, "dummy", line="line")
self.assertEqual("line", f.line)

def test_explicit_multiline_line(self):
f = traceback.FrameSummary("f", 1, "dummy", line="line 1\nline 2")
self.assertEqual("line 1", f.line)

def test_len(self):
f = traceback.FrameSummary("f", 1, "dummy", line="line")
self.assertEqual(len(f), 4)
Expand Down Expand Up @@ -3415,6 +3419,46 @@ def test_from_list(self):
[' File "foo.py", line 1, in fred\n line\n'],
s.format())

def test_from_list_multiline_without_columns(self):
frame = traceback.FrameSummary(
'foo.py', 1, 'fred', line='line 1\nline 2')
s = traceback.StackSummary.from_list([frame])
self.assertEqual(
[' File "foo.py", line 1, in fred\n line 1\n'],
s.format())

def test_from_list_multiline_with_columns(self):
frame = traceback.FrameSummary(
'foo.py', 1, 'fred', line='line 1\nline 2',
end_lineno=2, colno=0, end_colno=6)
s = traceback.StackSummary.from_list([frame])
self.assertEqual(
[' File "foo.py", line 1, in fred\n'
' line 1\n'
' line 2\n'],
s.format())

def test_from_list_multiline_with_columns_without_end_lineno(self):
# end_lineno defaults to lineno, so the frame spans a single line
# and the trailing physical lines are not displayed.
frame = traceback.FrameSummary(
'foo.py', 1, 'fred', line='line 1\nline 2',
colno=0, end_colno=6)
s = traceback.StackSummary.from_list([frame])
self.assertEqual(
[' File "foo.py", line 1, in fred\n line 1\n'],
s.format())

def test_format_list_multiline_old_style_tuple(self):
frames = [
('test.py', 10, 'func',
'x = foo + bar\n\t\thello\n\tworld'),
]
self.assertEqual(
[' File "test.py", line 10, in func\n'
' x = foo + bar\n'],
traceback.format_list(frames))

def test_from_list_edited_stack(self):
s = traceback.StackSummary.from_list([('foo.py', 1, 'fred', 'line')])
s[0] = ('foo.py', 2, 'fred', 'line')
Expand Down
25 changes: 18 additions & 7 deletions Lib/traceback.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,12 @@ def format_list(extracted_list):
for printing.

Each string in the resulting list corresponds to the item with the
same index in the argument list. Each string ends in a newline;
the strings may contain internal newlines as well, for those items
whose source text line is not None.
same index in the argument list. Each string ends in a newline and may
contain internal newlines. When an item's source text spans multiple
physical lines, every line is displayed only if the item has both column
position information and an end line number greater than its line number;
otherwise just the first physical line is displayed. Old-style tuples
never have column position information.
"""
return StackSummary.from_list(extracted_list).format()

Expand Down Expand Up @@ -324,8 +327,8 @@ class FrameSummary:
active when the frame was captured.
- :attr:`name` The name of the function or method that was executing
when the frame was captured.
- :attr:`line` The text from the linecache module for the line
of code that was running when the frame was captured.
- :attr:`line` The first physical line of code that was running when
the frame was captured.
- :attr:`locals` Either None if locals were not supplied, or a dict
mapping the name to the repr() of the variable.
- :attr:`end_lineno` The last line number of the source code for this frame.
Expand Down Expand Up @@ -558,6 +561,11 @@ def from_list(klass, a_list):
"""
Create a StackSummary object from a supplied list of
FrameSummary objects or old-style list of tuples.

Old-style tuples do not have column position information, so only the
first physical line of the line element is displayed when they are
formatted. The same applies to FrameSummary objects without column
position information.
"""
# While doing a fast-path check for isinstance(a_list, StackSummary) is
# appealing, idlelib.run.cleanup_traceback and other similar code may
Expand Down Expand Up @@ -794,8 +802,11 @@ def format(self, **kwargs):

Returns a list of strings ready for printing. Each string in the
resulting list corresponds to a single frame from the stack.
Each string ends in a newline; the strings may contain internal
newlines as well, for those items with source text lines.
Each string ends in a newline and may contain internal newlines. When
a frame's source text spans multiple physical lines, every line is
displayed only if the frame has both column position information and an
end line number greater than its line number; otherwise just the first
physical line is displayed.

For long sequences of the same frame and line, the first few
repetitions are shown, followed by a summary line stating the exact
Expand Down
Loading