summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_trace.py6
-rw-r--r--Lib/test/test_traceback.py45
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2021-12-10-13-42-17.bpo-37971.6BC1Tx.rst3
-rw-r--r--Python/compile.c33
4 files changed, 76 insertions, 11 deletions
diff --git a/Lib/test/test_trace.py b/Lib/test/test_trace.py
index d63c177..5f71211 100644
--- a/Lib/test/test_trace.py
+++ b/Lib/test/test_trace.py
@@ -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,
}
diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py
index a458b21..97bd9ba 100644
--- a/Lib/test/test_traceback.py
+++ b/Lib/test/test_traceback.py
@@ -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()
diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-12-10-13-42-17.bpo-37971.6BC1Tx.rst b/Misc/NEWS.d/next/Core and Builtins/2021-12-10-13-42-17.bpo-37971.6BC1Tx.rst
new file mode 100644
index 0000000..17f44f0
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2021-12-10-13-42-17.bpo-37971.6BC1Tx.rst
@@ -0,0 +1,3 @@
+Fix a bug where the line numbers given in a traceback when a decorator
+application raised an exception were wrong.
+
diff --git a/Python/compile.c b/Python/compile.c
index 6138031..bbdb011 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -2133,6 +2133,27 @@ compiler_decorators(struct compiler *c, asdl_expr_seq* decos)
}
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))