Skip to content

Commit b593bdc

Browse files
cfbolzambv
andauthored
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 <[email protected]>
1 parent 28179aa commit b593bdc

File tree

4 files changed

+76
-11
lines changed

4 files changed

+76
-11
lines changed

Lib/test/test_trace.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,9 @@ def test_traced_decorated_function(self):
205205
(self.my_py_filename, firstlineno + 4): 1,
206206
(self.my_py_filename, firstlineno + 5): 1,
207207
(self.my_py_filename, firstlineno + 6): 1,
208-
(self.my_py_filename, firstlineno + 7): 1,
209-
(self.my_py_filename, firstlineno + 8): 1,
210-
(self.my_py_filename, firstlineno + 9): 1,
208+
(self.my_py_filename, firstlineno + 7): 2,
209+
(self.my_py_filename, firstlineno + 8): 2,
210+
(self.my_py_filename, firstlineno + 9): 2,
211211
(self.my_py_filename, firstlineno + 10): 1,
212212
(self.my_py_filename, firstlineno + 11): 1,
213213
}

Lib/test/test_traceback.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,51 @@ def test_specialization_variations(self):
616616
self.assertSpecialized(lambda: 1// 0,
617617
"~^^~~")
618618

619+
def test_decorator_application_lineno_correct(self):
620+
def dec_error(func):
621+
raise TypeError
622+
def dec_fine(func):
623+
return func
624+
def applydecs():
625+
@dec_error
626+
@dec_fine
627+
def g(): pass
628+
result_lines = self.get_exception(applydecs)
629+
lineno_applydescs = applydecs.__code__.co_firstlineno
630+
lineno_dec_error = dec_error.__code__.co_firstlineno
631+
expected_error = (
632+
'Traceback (most recent call last):\n'
633+
f' File "{__file__}", line {self.callable_line}, in get_exception\n'
634+
' callable()\n'
635+
' ^^^^^^^^^^\n'
636+
f' File "{__file__}", line {lineno_applydescs + 1}, in applydecs\n'
637+
' @dec_error\n'
638+
' ^^^^^^^^^\n'
639+
f' File "{__file__}", line {lineno_dec_error + 1}, in dec_error\n'
640+
' raise TypeError\n'
641+
' ^^^^^^^^^^^^^^^\n'
642+
)
643+
self.assertEqual(result_lines, expected_error.splitlines())
644+
645+
def applydecs_class():
646+
@dec_error
647+
@dec_fine
648+
class A: pass
649+
result_lines = self.get_exception(applydecs_class)
650+
lineno_applydescs_class = applydecs_class.__code__.co_firstlineno
651+
expected_error = (
652+
'Traceback (most recent call last):\n'
653+
f' File "{__file__}", line {self.callable_line}, in get_exception\n'
654+
' callable()\n'
655+
' ^^^^^^^^^^\n'
656+
f' File "{__file__}", line {lineno_applydescs_class + 1}, in applydecs_class\n'
657+
' @dec_error\n'
658+
' ^^^^^^^^^\n'
659+
f' File "{__file__}", line {lineno_dec_error + 1}, in dec_error\n'
660+
' raise TypeError\n'
661+
' ^^^^^^^^^^^^^^^\n'
662+
)
663+
self.assertEqual(result_lines, expected_error.splitlines())
619664

620665
@cpython_only
621666
@requires_debug_ranges()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix a bug where the line numbers given in a traceback when a decorator
2+
application raised an exception were wrong.
3+

Python/compile.c

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2132,6 +2132,27 @@ compiler_decorators(struct compiler *c, asdl_expr_seq* decos)
21322132
return 1;
21332133
}
21342134

2135+
static int
2136+
compiler_apply_decorators(struct compiler *c, asdl_expr_seq* decos)
2137+
{
2138+
if (!decos)
2139+
return 1;
2140+
2141+
int old_lineno = c->u->u_lineno;
2142+
int old_end_lineno = c->u->u_end_lineno;
2143+
int old_col_offset = c->u->u_col_offset;
2144+
int old_end_col_offset = c->u->u_end_col_offset;
2145+
for (Py_ssize_t i = asdl_seq_LEN(decos) - 1; i > -1; i--) {
2146+
SET_LOC(c, (expr_ty)asdl_seq_GET(decos, i));
2147+
ADDOP_I(c, CALL_FUNCTION, 1);
2148+
}
2149+
c->u->u_lineno = old_lineno;
2150+
c->u->u_end_lineno = old_end_lineno;
2151+
c->u->u_col_offset = old_col_offset;
2152+
c->u->u_end_col_offset = old_end_col_offset;
2153+
return 1;
2154+
}
2155+
21352156
static int
21362157
compiler_visit_kwonlydefaults(struct compiler *c, asdl_arg_seq *kwonlyargs,
21372158
asdl_expr_seq *kw_defaults)
@@ -2462,11 +2483,8 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async)
24622483
Py_DECREF(qualname);
24632484
Py_DECREF(co);
24642485

2465-
/* decorators */
2466-
for (i = 0; i < asdl_seq_LEN(decos); i++) {
2467-
ADDOP_I(c, CALL_FUNCTION, 1);
2468-
}
2469-
2486+
if (!compiler_apply_decorators(c, decos))
2487+
return 0;
24702488
return compiler_nameop(c, name, Store);
24712489
}
24722490

@@ -2597,9 +2615,8 @@ compiler_class(struct compiler *c, stmt_ty s)
25972615
return 0;
25982616

25992617
/* 6. apply decorators */
2600-
for (i = 0; i < asdl_seq_LEN(decos); i++) {
2601-
ADDOP_I(c, CALL_FUNCTION, 1);
2602-
}
2618+
if (!compiler_apply_decorators(c, decos))
2619+
return 0;
26032620

26042621
/* 7. store into <name> */
26052622
if (!compiler_nameop(c, s->v.ClassDef.name, Store))

0 commit comments

Comments
 (0)