diff options
author | Batuhan Taskaya <batuhan@python.org> | 2021-07-12 19:32:33 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-12 19:32:33 (GMT) |
commit | 1890dd235f618d60c938f6904d2e1a8a56f99c1c (patch) | |
tree | 48aae356623a4647892f3dde5edcd8949a87b23e /Lib/traceback.py | |
parent | da2e673c53974641a0e13941950e7976bbda64d5 (diff) | |
download | cpython-1890dd235f618d60c938f6904d2e1a8a56f99c1c.zip cpython-1890dd235f618d60c938f6904d2e1a8a56f99c1c.tar.gz cpython-1890dd235f618d60c938f6904d2e1a8a56f99c1c.tar.bz2 |
bpo-43950: Specialize tracebacks for subscripts/binary ops (GH-27037)
Co-authored-by: Ammar Askar <ammar@ammaraskar.com>
Co-authored-by: Pablo Galindo <pablogsal@gmail.com>
Diffstat (limited to 'Lib/traceback.py')
-rw-r--r-- | Lib/traceback.py | 60 |
1 files changed, 59 insertions, 1 deletions
diff --git a/Lib/traceback.py b/Lib/traceback.py index 7cb1241..ec5e20d 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -494,9 +494,23 @@ class StackSummary(list): colno = _byte_offset_to_character_offset(frame._original_line, frame.colno) end_colno = _byte_offset_to_character_offset(frame._original_line, frame.end_colno) + try: + anchors = _extract_caret_anchors_from_line_segment( + frame._original_line[colno - 1:end_colno] + ) + except Exception: + anchors = None + row.append(' ') row.append(' ' * (colno - stripped_characters)) - row.append('^' * (end_colno - colno)) + + if anchors: + row.append(anchors.primary_char * (anchors.left_end_offset)) + row.append(anchors.secondary_char * (anchors.right_start_offset - anchors.left_end_offset)) + row.append(anchors.primary_char * (end_colno - colno - anchors.right_start_offset)) + else: + row.append('^' * (end_colno - colno)) + row.append('\n') if frame.locals: @@ -520,6 +534,50 @@ def _byte_offset_to_character_offset(str, offset): return len(as_utf8[:offset + 1].decode("utf-8")) +_Anchors = collections.namedtuple( + "_Anchors", + [ + "left_end_offset", + "right_start_offset", + "primary_char", + "secondary_char", + ], + defaults=["~", "^"] +) + +def _extract_caret_anchors_from_line_segment(segment): + import ast + + try: + tree = ast.parse(segment) + except SyntaxError: + return None + + if len(tree.body) != 1: + return None + + statement = tree.body[0] + match statement: + case ast.Expr(expr): + match expr: + case ast.BinOp(): + operator_str = segment[expr.left.end_col_offset:expr.right.col_offset] + operator_offset = len(operator_str) - len(operator_str.lstrip()) + + left_anchor = expr.left.end_col_offset + operator_offset + right_anchor = left_anchor + 1 + if ( + operator_offset + 1 < len(operator_str) + and not operator_str[operator_offset + 1].isspace() + ): + right_anchor += 1 + return _Anchors(left_anchor, right_anchor) + case ast.Subscript(): + return _Anchors(expr.value.end_col_offset, expr.slice.end_col_offset + 1) + + return None + + class TracebackException: """An exception ready for rendering. |