From 0b58e863df9970b290a4de90c67f9ac30c443817 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Fri, 3 Sep 2021 22:39:23 +0100 Subject: =?UTF-8?q?bpo-45075:=20distinguish=20between=20frame=20and=20Fram?= =?UTF-8?q?eSummary=20in=20traceback=20mo=E2=80=A6=20(GH-28112)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Doc/library/traceback.rst | 10 ++-- Lib/test/test_traceback.py | 10 ++-- Lib/traceback.py | 62 ++++++++++++---------- .../2021-09-01-15-27-00.bpo-45075.9xUpvt.rst | 5 ++ 4 files changed, 48 insertions(+), 39 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2021-09-01-15-27-00.bpo-45075.9xUpvt.rst diff --git a/Doc/library/traceback.rst b/Doc/library/traceback.rst index 7b23049..df4a38c 100644 --- a/Doc/library/traceback.rst +++ b/Doc/library/traceback.rst @@ -353,12 +353,12 @@ capture data for later printing in a lightweight fashion. .. versionchanged:: 3.6 Long sequences of repeated frames are now abbreviated. - .. method:: format_frame(frame) + .. method:: format_frame_summary(frame_summary) Returns a string for printing one of the frames involved in the stack. - This method gets called for each frame object to be printed in the - :class:`StackSummary`. If it returns ``None``, the frame is omitted - from the output. + This method is called for each :class:`FrameSummary` object to be + printed by :meth:`StackSummary.format`. If it returns ``None``, the + frame is omitted from the output. .. versionadded:: 3.11 @@ -368,7 +368,7 @@ capture data for later printing in a lightweight fashion. .. versionadded:: 3.5 -:class:`FrameSummary` objects represent a single frame in a traceback. +A :class:`FrameSummary` object represents a single frame in a traceback. .. class:: FrameSummary(filename, lineno, name, lookup_line=True, locals=None, line=None) diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index ee2896c..949adef 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -1515,8 +1515,8 @@ class TestStack(unittest.TestCase): def test_custom_format_frame(self): class CustomStackSummary(traceback.StackSummary): - def format_frame(self, frame): - return f'{frame.filename}:{frame.lineno}' + def format_frame_summary(self, frame_summary): + return f'{frame_summary.filename}:{frame_summary.lineno}' def some_inner(): return CustomStackSummary.extract( @@ -1540,10 +1540,10 @@ class TestStack(unittest.TestCase): exc_info = g() class Skip_G(traceback.StackSummary): - def format_frame(self, frame): - if frame.name == 'g': + def format_frame_summary(self, frame_summary): + if frame_summary.name == 'g': return None - return super().format_frame(frame) + return super().format_frame_summary(frame_summary) stack = Skip_G.extract( traceback.walk_tb(exc_info[2])).format() diff --git a/Lib/traceback.py b/Lib/traceback.py index 8d83fd9..d51c201 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -240,7 +240,7 @@ def clear_frames(tb): class FrameSummary: - """A single frame from a traceback. + """Information about a single frame from a traceback. - :attr:`filename` The filename for the frame. - :attr:`lineno` The line within filename for the frame that was @@ -365,15 +365,15 @@ def _get_code_position(code, instruction_index): _RECURSIVE_CUTOFF = 3 # Also hardcoded in traceback.c. class StackSummary(list): - """A stack of frames.""" + """A list of FrameSummary objects, representing a stack of frames.""" @classmethod def extract(klass, frame_gen, *, limit=None, lookup_lines=True, capture_locals=False): """Create a StackSummary from a traceback or stack object. - :param frame_gen: A generator that yields (frame, lineno) tuples to - include in the stack. + :param frame_gen: A generator that yields (frame, lineno) tuples + whose summaries are to be included in the stack. :param limit: None to include all frames or the number of frames to include. :param lookup_lines: If True, lookup lines for each frame immediately, @@ -394,7 +394,7 @@ class StackSummary(list): lookup_lines=True, capture_locals=False): # Same as extract but operates on a frame generator that yields # (frame, (lineno, end_lineno, colno, end_colno)) in the stack. - # Only lineno is required, the remaining fields can be empty if the + # Only lineno is required, the remaining fields can be None if the # information is not available. if limit is None: limit = getattr(sys, 'tracebacklimit', None) @@ -450,34 +450,38 @@ class StackSummary(list): result.append(FrameSummary(filename, lineno, name, line=line)) return result - def format_frame(self, frame): - """Format the lines for a single frame. + def format_frame_summary(self, frame_summary): + """Format the lines for a single FrameSummary. Returns a string representing one frame involved in the stack. This gets called for every frame to be printed in the stack summary. """ row = [] row.append(' File "{}", line {}, in {}\n'.format( - frame.filename, frame.lineno, frame.name)) - if frame.line: - row.append(' {}\n'.format(frame.line.strip())) + frame_summary.filename, frame_summary.lineno, frame_summary.name)) + if frame_summary.line: + row.append(' {}\n'.format(frame_summary.line.strip())) - stripped_characters = len(frame._original_line) - len(frame.line.lstrip()) + orig_line_len = len(frame_summary._original_line) + frame_line_len = len(frame_summary.line.lstrip()) + stripped_characters = orig_line_len - frame_line_len if ( - frame.colno is not None - and frame.end_colno is not None + frame_summary.colno is not None + and frame_summary.end_colno is not None ): - colno = _byte_offset_to_character_offset(frame._original_line, frame.colno) - end_colno = _byte_offset_to_character_offset(frame._original_line, frame.end_colno) + colno = _byte_offset_to_character_offset( + frame_summary._original_line, frame_summary.colno) + end_colno = _byte_offset_to_character_offset( + frame_summary._original_line, frame_summary.end_colno) anchors = None - if frame.lineno == frame.end_lineno: + if frame_summary.lineno == frame_summary.end_lineno: with suppress(Exception): anchors = _extract_caret_anchors_from_line_segment( - frame._original_line[colno - 1:end_colno - 1] + frame_summary._original_line[colno - 1:end_colno - 1] ) else: - end_colno = stripped_characters + len(frame.line.strip()) + end_colno = stripped_characters + len(frame_summary.line.strip()) row.append(' ') row.append(' ' * (colno - stripped_characters)) @@ -491,8 +495,8 @@ class StackSummary(list): row.append('\n') - if frame.locals: - for name, value in sorted(frame.locals.items()): + if frame_summary.locals: + for name, value in sorted(frame_summary.locals.items()): row.append(' {name} = {value}\n'.format(name=name, value=value)) return ''.join(row) @@ -514,27 +518,27 @@ class StackSummary(list): last_line = None last_name = None count = 0 - for frame in self: - formatted_frame = self.format_frame(frame) + for frame_summary in self: + formatted_frame = self.format_frame_summary(frame_summary) if formatted_frame is None: continue - if (last_file is None or last_file != frame.filename or - last_line is None or last_line != frame.lineno or - last_name is None or last_name != frame.name): + if (last_file is None or last_file != frame_summary.filename or + last_line is None or last_line != frame_summary.lineno or + last_name is None or last_name != frame_summary.name): if count > _RECURSIVE_CUTOFF: count -= _RECURSIVE_CUTOFF result.append( f' [Previous line repeated {count} more ' f'time{"s" if count > 1 else ""}]\n' ) - last_file = frame.filename - last_line = frame.lineno - last_name = frame.name + last_file = frame_summary.filename + last_line = frame_summary.lineno + last_name = frame_summary.name count = 0 count += 1 if count > _RECURSIVE_CUTOFF: continue - result.append(self.format_frame(frame)) + result.append(formatted_frame) if count > _RECURSIVE_CUTOFF: count -= _RECURSIVE_CUTOFF diff --git a/Misc/NEWS.d/next/Library/2021-09-01-15-27-00.bpo-45075.9xUpvt.rst b/Misc/NEWS.d/next/Library/2021-09-01-15-27-00.bpo-45075.9xUpvt.rst new file mode 100644 index 0000000..369b450 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-09-01-15-27-00.bpo-45075.9xUpvt.rst @@ -0,0 +1,5 @@ +Rename :meth:`traceback.StackSummary.format_frame` to +:meth:`traceback.StackSummary.format_frame_summary`. This method was added +for 3.11 so it was not released yet. + +Updated code and docs to better distinguish frame and FrameSummary. -- cgit v0.12