mirror of https://github.com/python/cpython.git
[3.11] gh-106922: Fix error location for constructs with spaces and parentheses (GH-108959) (#109148)
Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com>
This commit is contained in:
parent
b55cf2c2d8
commit
c1a2ef5efc
|
@ -566,6 +566,24 @@ def f_with_binary_operator():
|
||||||
result_lines = self.get_exception(f_with_binary_operator)
|
result_lines = self.get_exception(f_with_binary_operator)
|
||||||
self.assertEqual(result_lines, expected_error.splitlines())
|
self.assertEqual(result_lines, expected_error.splitlines())
|
||||||
|
|
||||||
|
def test_caret_for_binary_operators_with_spaces_and_parenthesis(self):
|
||||||
|
def f_with_binary_operator():
|
||||||
|
a = 1
|
||||||
|
b = ""
|
||||||
|
return ( a ) + b
|
||||||
|
|
||||||
|
lineno_f = f_with_binary_operator.__code__.co_firstlineno
|
||||||
|
expected_error = (
|
||||||
|
'Traceback (most recent call last):\n'
|
||||||
|
f' File "{__file__}", line {self.callable_line}, in get_exception\n'
|
||||||
|
' callable()\n'
|
||||||
|
f' File "{__file__}", line {lineno_f+3}, in f_with_binary_operator\n'
|
||||||
|
' return ( a ) + b\n'
|
||||||
|
' ~~~~~~~~~~^~~\n'
|
||||||
|
)
|
||||||
|
result_lines = self.get_exception(f_with_binary_operator)
|
||||||
|
self.assertEqual(result_lines, expected_error.splitlines())
|
||||||
|
|
||||||
def test_caret_for_subscript(self):
|
def test_caret_for_subscript(self):
|
||||||
def f_with_subscript():
|
def f_with_subscript():
|
||||||
some_dict = {'x': {'y': None}}
|
some_dict = {'x': {'y': None}}
|
||||||
|
@ -600,6 +618,24 @@ def f_with_subscript():
|
||||||
result_lines = self.get_exception(f_with_subscript)
|
result_lines = self.get_exception(f_with_subscript)
|
||||||
self.assertEqual(result_lines, expected_error.splitlines())
|
self.assertEqual(result_lines, expected_error.splitlines())
|
||||||
|
|
||||||
|
def test_caret_for_subscript_with_spaces_and_parenthesis(self):
|
||||||
|
def f_with_binary_operator():
|
||||||
|
a = []
|
||||||
|
b = c = 1
|
||||||
|
return b [ a ] + c
|
||||||
|
|
||||||
|
lineno_f = f_with_binary_operator.__code__.co_firstlineno
|
||||||
|
expected_error = (
|
||||||
|
'Traceback (most recent call last):\n'
|
||||||
|
f' File "{__file__}", line {self.callable_line}, in get_exception\n'
|
||||||
|
' callable()\n'
|
||||||
|
f' File "{__file__}", line {lineno_f+3}, in f_with_binary_operator\n'
|
||||||
|
' return b [ a ] + c\n'
|
||||||
|
' ~~~~~~^^^^^^^^^\n'
|
||||||
|
)
|
||||||
|
result_lines = self.get_exception(f_with_binary_operator)
|
||||||
|
self.assertEqual(result_lines, expected_error.splitlines())
|
||||||
|
|
||||||
def test_traceback_specialization_with_syntax_error(self):
|
def test_traceback_specialization_with_syntax_error(self):
|
||||||
bytecode = compile("1 / 0 / 1 / 2\n", TESTFN, "exec")
|
bytecode = compile("1 / 0 / 1 / 2\n", TESTFN, "exec")
|
||||||
|
|
||||||
|
|
|
@ -603,11 +603,21 @@ def _extract_caret_anchors_from_line_segment(segment):
|
||||||
and not operator_str[operator_offset + 1].isspace()
|
and not operator_str[operator_offset + 1].isspace()
|
||||||
):
|
):
|
||||||
right_anchor += 1
|
right_anchor += 1
|
||||||
|
|
||||||
|
while left_anchor < len(segment) and ((ch := segment[left_anchor]).isspace() or ch in ")#"):
|
||||||
|
left_anchor += 1
|
||||||
|
right_anchor += 1
|
||||||
return _Anchors(normalize(left_anchor), normalize(right_anchor))
|
return _Anchors(normalize(left_anchor), normalize(right_anchor))
|
||||||
case ast.Subscript():
|
case ast.Subscript():
|
||||||
subscript_start = normalize(expr.value.end_col_offset)
|
left_anchor = normalize(expr.value.end_col_offset)
|
||||||
subscript_end = normalize(expr.slice.end_col_offset + 1)
|
right_anchor = normalize(expr.slice.end_col_offset + 1)
|
||||||
return _Anchors(subscript_start, subscript_end)
|
while left_anchor < len(segment) and ((ch := segment[left_anchor]).isspace() or ch != "["):
|
||||||
|
left_anchor += 1
|
||||||
|
while right_anchor < len(segment) and ((ch := segment[right_anchor]).isspace() or ch != "]"):
|
||||||
|
right_anchor += 1
|
||||||
|
if right_anchor < len(segment):
|
||||||
|
right_anchor += 1
|
||||||
|
return _Anchors(left_anchor, right_anchor)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Fix caret placement for error locations for subscript and binary operations
|
||||||
|
that involve non-semantic parentheses and spaces. Patch by Pablo Galindo
|
|
@ -621,6 +621,11 @@ extract_anchors_from_expr(const char *segment_str, expr_ty expr, Py_ssize_t *lef
|
||||||
++*right_anchor;
|
++*right_anchor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep going if the current char is not ')'
|
||||||
|
if (i+1 < right->col_offset && (segment_str[i] == ')')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the error characters
|
// Set the error characters
|
||||||
*primary_error_char = "~";
|
*primary_error_char = "~";
|
||||||
*secondary_error_char = "^";
|
*secondary_error_char = "^";
|
||||||
|
@ -631,6 +636,18 @@ extract_anchors_from_expr(const char *segment_str, expr_ty expr, Py_ssize_t *lef
|
||||||
case Subscript_kind: {
|
case Subscript_kind: {
|
||||||
*left_anchor = expr->v.Subscript.value->end_col_offset;
|
*left_anchor = expr->v.Subscript.value->end_col_offset;
|
||||||
*right_anchor = expr->v.Subscript.slice->end_col_offset + 1;
|
*right_anchor = expr->v.Subscript.slice->end_col_offset + 1;
|
||||||
|
Py_ssize_t str_len = strlen(segment_str);
|
||||||
|
|
||||||
|
// Move right_anchor and left_anchor forward to the first non-whitespace character that is not ']' and '['
|
||||||
|
while (*left_anchor < str_len && (IS_WHITESPACE(segment_str[*left_anchor]) || segment_str[*left_anchor] != '[')) {
|
||||||
|
++*left_anchor;
|
||||||
|
}
|
||||||
|
while (*right_anchor < str_len && (IS_WHITESPACE(segment_str[*right_anchor]) || segment_str[*right_anchor] != ']')) {
|
||||||
|
++*right_anchor;
|
||||||
|
}
|
||||||
|
if (*right_anchor < str_len){
|
||||||
|
*right_anchor += 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the error characters
|
// Set the error characters
|
||||||
*primary_error_char = "~";
|
*primary_error_char = "~";
|
||||||
|
|
Loading…
Reference in New Issue