]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-37971: fix the position of decorator application (GH-30027)
authorCarl Friedrich Bolz-Tereick <cfbolz@gmx.de>
Fri, 10 Dec 2021 23:45:02 +0000 (00:45 +0100)
committerGitHub <noreply@github.com>
Fri, 10 Dec 2021 23:45:02 +0000 (00:45 +0100)
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>
Lib/test/test_trace.py
Lib/test/test_traceback.py
Misc/NEWS.d/next/Core and Builtins/2021-12-10-13-42-17.bpo-37971.6BC1Tx.rst [new file with mode: 0644]
Python/compile.c

index d63c1778c9d0815d9aaa9a9c49ed3614233dd8fc..5f712111ca14e05897ddbf40210ba35a2bf9fcf8 100644 (file)
@@ -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,
         }
index a458b21b094660f7771beb88bb44f7e2a3c0097b..97bd9bae1d58e45c0e4cf76e75f87c35d1b570bf 100644 (file)
@@ -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 (file)
index 0000000..17f44f0
--- /dev/null
@@ -0,0 +1,3 @@
+Fix a bug where the line numbers given in a traceback when a decorator
+application raised an exception were wrong.
+
index 6138031833ac93483721d7fcf1f1e17b1fa4cc16..bbdb0115be3bec8ca1d62cc3e55fac3b172b97b7 100644 (file)
@@ -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))