mirror of https://github.com/python/cpython
bpo-37971: fix the position of decorator application (GH-30027)
The line numbers of actually calling the decorator functions of functions and classes was wrong (as opposed to loading them, were they have been correct previously too). Co-authored-by: Łukasz Langa <lukasz@langa.pl>
This commit is contained in:
parent
28179aac79
commit
b593bdc780
|
@ -205,9 +205,9 @@ class TestLineCounts(unittest.TestCase):
|
|||
(self.my_py_filename, firstlineno + 4): 1,
|
||||
(self.my_py_filename, firstlineno + 5): 1,
|
||||
(self.my_py_filename, firstlineno + 6): 1,
|
||||
(self.my_py_filename, firstlineno + 7): 1,
|
||||
(self.my_py_filename, firstlineno + 8): 1,
|
||||
(self.my_py_filename, firstlineno + 9): 1,
|
||||
(self.my_py_filename, firstlineno + 7): 2,
|
||||
(self.my_py_filename, firstlineno + 8): 2,
|
||||
(self.my_py_filename, firstlineno + 9): 2,
|
||||
(self.my_py_filename, firstlineno + 10): 1,
|
||||
(self.my_py_filename, firstlineno + 11): 1,
|
||||
}
|
||||
|
|
|
@ -616,6 +616,51 @@ class TracebackErrorLocationCaretTests(unittest.TestCase):
|
|||
self.assertSpecialized(lambda: 1// 0,
|
||||
"~^^~~")
|
||||
|
||||
def test_decorator_application_lineno_correct(self):
|
||||
def dec_error(func):
|
||||
raise TypeError
|
||||
def dec_fine(func):
|
||||
return func
|
||||
def applydecs():
|
||||
@dec_error
|
||||
@dec_fine
|
||||
def g(): pass
|
||||
result_lines = self.get_exception(applydecs)
|
||||
lineno_applydescs = applydecs.__code__.co_firstlineno
|
||||
lineno_dec_error = dec_error.__code__.co_firstlineno
|
||||
expected_error = (
|
||||
'Traceback (most recent call last):\n'
|
||||
f' File "{__file__}", line {self.callable_line}, in get_exception\n'
|
||||
' callable()\n'
|
||||
' ^^^^^^^^^^\n'
|
||||
f' File "{__file__}", line {lineno_applydescs + 1}, in applydecs\n'
|
||||
' @dec_error\n'
|
||||
' ^^^^^^^^^\n'
|
||||
f' File "{__file__}", line {lineno_dec_error + 1}, in dec_error\n'
|
||||
' raise TypeError\n'
|
||||
' ^^^^^^^^^^^^^^^\n'
|
||||
)
|
||||
self.assertEqual(result_lines, expected_error.splitlines())
|
||||
|
||||
def applydecs_class():
|
||||
@dec_error
|
||||
@dec_fine
|
||||
class A: pass
|
||||
result_lines = self.get_exception(applydecs_class)
|
||||
lineno_applydescs_class = applydecs_class.__code__.co_firstlineno
|
||||
expected_error = (
|
||||
'Traceback (most recent call last):\n'
|
||||
f' File "{__file__}", line {self.callable_line}, in get_exception\n'
|
||||
' callable()\n'
|
||||
' ^^^^^^^^^^\n'
|
||||
f' File "{__file__}", line {lineno_applydescs_class + 1}, in applydecs_class\n'
|
||||
' @dec_error\n'
|
||||
' ^^^^^^^^^\n'
|
||||
f' File "{__file__}", line {lineno_dec_error + 1}, in dec_error\n'
|
||||
' raise TypeError\n'
|
||||
' ^^^^^^^^^^^^^^^\n'
|
||||
)
|
||||
self.assertEqual(result_lines, expected_error.splitlines())
|
||||
|
||||
@cpython_only
|
||||
@requires_debug_ranges()
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Fix a bug where the line numbers given in a traceback when a decorator
|
||||
application raised an exception were wrong.
|
||||
|
|
@ -2132,6 +2132,27 @@ compiler_decorators(struct compiler *c, asdl_expr_seq* decos)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
compiler_apply_decorators(struct compiler *c, asdl_expr_seq* decos)
|
||||
{
|
||||
if (!decos)
|
||||
return 1;
|
||||
|
||||
int old_lineno = c->u->u_lineno;
|
||||
int old_end_lineno = c->u->u_end_lineno;
|
||||
int old_col_offset = c->u->u_col_offset;
|
||||
int old_end_col_offset = c->u->u_end_col_offset;
|
||||
for (Py_ssize_t i = asdl_seq_LEN(decos) - 1; i > -1; i--) {
|
||||
SET_LOC(c, (expr_ty)asdl_seq_GET(decos, i));
|
||||
ADDOP_I(c, CALL_FUNCTION, 1);
|
||||
}
|
||||
c->u->u_lineno = old_lineno;
|
||||
c->u->u_end_lineno = old_end_lineno;
|
||||
c->u->u_col_offset = old_col_offset;
|
||||
c->u->u_end_col_offset = old_end_col_offset;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
compiler_visit_kwonlydefaults(struct compiler *c, asdl_arg_seq *kwonlyargs,
|
||||
asdl_expr_seq *kw_defaults)
|
||||
|
@ -2462,11 +2483,8 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async)
|
|||
Py_DECREF(qualname);
|
||||
Py_DECREF(co);
|
||||
|
||||
/* decorators */
|
||||
for (i = 0; i < asdl_seq_LEN(decos); i++) {
|
||||
ADDOP_I(c, CALL_FUNCTION, 1);
|
||||
}
|
||||
|
||||
if (!compiler_apply_decorators(c, decos))
|
||||
return 0;
|
||||
return compiler_nameop(c, name, Store);
|
||||
}
|
||||
|
||||
|
@ -2597,9 +2615,8 @@ compiler_class(struct compiler *c, stmt_ty s)
|
|||
return 0;
|
||||
|
||||
/* 6. apply decorators */
|
||||
for (i = 0; i < asdl_seq_LEN(decos); i++) {
|
||||
ADDOP_I(c, CALL_FUNCTION, 1);
|
||||
}
|
||||
if (!compiler_apply_decorators(c, decos))
|
||||
return 0;
|
||||
|
||||
/* 7. store into <name> */
|
||||
if (!compiler_nameop(c, s->v.ClassDef.name, Store))
|
||||
|
|
Loading…
Reference in New Issue