[Python-checkins] bpo-39316: Make sure that attribute accesses and stores, including method calls, conform to PEP 626. (GH-24859)

markshannon webhook-mailer at python.org
Sun Mar 14 14:01:48 EDT 2021


https://github.com/python/cpython/commit/d48848c83e0f3e41b65c8f741f3fb6dbce5b9c29
commit: d48848c83e0f3e41b65c8f741f3fb6dbce5b9c29
branch: master
author: Mark Shannon <mark at hotpy.org>
committer: markshannon <mark at hotpy.org>
date: 2021-03-14T18:01:30Z
summary:

bpo-39316: Make sure that attribute accesses and stores, including method calls, conform to PEP 626. (GH-24859)

files:
A Misc/NEWS.d/next/Core and Builtins/2021-03-14-16-44-50.bpo-39316.Ns3a_F.rst
M Lib/test/test_compile.py
M Python/compile.c
M Python/importlib.h
M Python/importlib_external.h

diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py
index 1f125242e156f..aa08c97c3ada8 100644
--- a/Lib/test/test_compile.py
+++ b/Lib/test/test_compile.py
@@ -837,6 +837,51 @@ def no_code2():
                 self.assertEqual(end, len(code.co_code))
                 self.assertEqual(line, code.co_firstlineno)
 
+    def test_lineno_attribute(self):
+        def load_attr():
+            return (
+                o.
+                a
+            )
+        load_attr_lines = [ 2, 3, 1 ]
+
+        def load_method():
+            return (
+                o.
+                m(
+                    0
+                )
+            )
+        load_method_lines = [ 2, 3, 4, 3, 1 ]
+
+        def store_attr():
+            (
+                o.
+                a
+            ) = (
+                v
+            )
+        store_attr_lines = [ 5, 2, 3 ]
+
+        def aug_store_attr():
+            (
+                o.
+                a
+            ) += (
+                v
+            )
+        aug_store_attr_lines = [ 2, 3, 5, 1, 3 ]
+
+        funcs = [ load_attr, load_method, store_attr, aug_store_attr]
+        func_lines = [ load_attr_lines, load_method_lines,
+                 store_attr_lines, aug_store_attr_lines]
+
+        for func, lines in zip(funcs, func_lines, strict=True):
+            with self.subTest(func=func):
+                code_lines = [ line-func.__code__.co_firstlineno
+                              for (_, _, line) in func.__code__.co_lines() ]
+                self.assertEqual(lines, code_lines)
+
 
     def test_big_dict_literal(self):
         # The compiler has a flushing point in "compiler_dict" that calls compiles
diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-03-14-16-44-50.bpo-39316.Ns3a_F.rst b/Misc/NEWS.d/next/Core and Builtins/2021-03-14-16-44-50.bpo-39316.Ns3a_F.rst
new file mode 100644
index 0000000000000..bebd9e83db435
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2021-03-14-16-44-50.bpo-39316.Ns3a_F.rst	
@@ -0,0 +1,3 @@
+Tracing now has correct line numbers for attribute accesses when the
+the attribute is on a different line from the object.
+Improves debugging and profiling for multi-line method chains.
diff --git a/Python/compile.c b/Python/compile.c
index a841288520b88..942614fdab850 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -4145,9 +4145,12 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
 
     /* Alright, we can optimize the code. */
     VISIT(c, expr, meth->v.Attribute.value);
+    int old_lineno = c->u->u_lineno;
+    c->u->u_lineno = meth->end_lineno;
     ADDOP_NAME(c, LOAD_METHOD, meth->v.Attribute.attr, names);
     VISIT_SEQ(c, expr, e->v.Call.args);
     ADDOP_I(c, CALL_METHOD, asdl_seq_LEN(e->v.Call.args));
+    c->u->u_lineno = old_lineno;
     return 1;
 }
 
@@ -5113,12 +5116,21 @@ compiler_visit_expr1(struct compiler *c, expr_ty e)
         VISIT(c, expr, e->v.Attribute.value);
         switch (e->v.Attribute.ctx) {
         case Load:
+        {
+            int old_lineno = c->u->u_lineno;
+            c->u->u_lineno = e->end_lineno;
             ADDOP_NAME(c, LOAD_ATTR, e->v.Attribute.attr, names);
+            c->u->u_lineno = old_lineno;
             break;
+        }
         case Store:
-            if (forbidden_name(c, e->v.Attribute.attr, e->v.Attribute.ctx))
+            if (forbidden_name(c, e->v.Attribute.attr, e->v.Attribute.ctx)) {
                 return 0;
+            }
+            int old_lineno = c->u->u_lineno;
+            c->u->u_lineno = e->end_lineno;
             ADDOP_NAME(c, STORE_ATTR, e->v.Attribute.attr, names);
+            c->u->u_lineno = old_lineno;
             break;
         case Del:
             ADDOP_NAME(c, DELETE_ATTR, e->v.Attribute.attr, names);
@@ -5182,7 +5194,10 @@ compiler_augassign(struct compiler *c, stmt_ty s)
     case Attribute_kind:
         VISIT(c, expr, e->v.Attribute.value);
         ADDOP(c, DUP_TOP);
+        int old_lineno = c->u->u_lineno;
+        c->u->u_lineno = e->end_lineno;
         ADDOP_NAME(c, LOAD_ATTR, e->v.Attribute.attr, names);
+        c->u->u_lineno = old_lineno;
         break;
     case Subscript_kind:
         VISIT(c, expr, e->v.Subscript.value);
@@ -5211,6 +5226,7 @@ compiler_augassign(struct compiler *c, stmt_ty s)
 
     switch (e->kind) {
     case Attribute_kind:
+        c->u->u_lineno = e->end_lineno;
         ADDOP(c, ROT_TWO);
         ADDOP_NAME(c, STORE_ATTR, e->v.Attribute.attr, names);
         break;
diff --git a/Python/importlib.h b/Python/importlib.h
index 880343bcda308..90cfa4cc2daed 100644
--- a/Python/importlib.h
+++ b/Python/importlib.h
@@ -694,7 +694,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = {
     218,4,106,111,105,110,41,2,114,33,0,0,0,114,62,0,
     0,0,114,5,0,0,0,114,5,0,0,0,114,6,0,0,
     0,114,53,0,0,0,123,1,0,0,115,22,0,0,0,10,
-    1,10,1,4,255,10,2,18,1,10,1,8,1,4,1,6,
+    1,10,1,4,255,10,2,18,1,10,1,6,1,8,1,4,
     255,22,2,255,128,122,19,77,111,100,117,108,101,83,112,101,
     99,46,95,95,114,101,112,114,95,95,99,2,0,0,0,0,
     0,0,0,0,0,0,0,3,0,0,0,8,0,0,0,67,
@@ -1552,8 +1552,8 @@ const unsigned char _Py_M__importlib_bootstrap[] = {
     0,114,82,0,0,0,114,5,0,0,0,114,5,0,0,0,
     114,6,0,0,0,218,14,95,102,105,110,100,95,97,110,100,
     95,108,111,97,100,253,3,0,0,115,28,0,0,0,10,2,
-    14,1,8,1,24,1,14,255,16,128,8,3,4,1,2,1,
-    4,255,12,2,8,2,4,1,255,128,114,227,0,0,0,114,
+    14,1,8,1,24,1,14,255,16,128,8,3,2,1,6,1,
+    2,255,12,2,8,2,4,1,255,128,114,227,0,0,0,114,
     25,0,0,0,99,3,0,0,0,0,0,0,0,0,0,0,
     0,3,0,0,0,4,0,0,0,67,0,0,0,115,42,0,
     0,0,116,0,124,0,124,1,124,2,131,3,1,0,124,2,
diff --git a/Python/importlib_external.h b/Python/importlib_external.h
index 108f59e2631c4..f9045892885f2 100644
--- a/Python/importlib_external.h
+++ b/Python/importlib_external.h
@@ -1173,8 +1173,8 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = {
     3,114,130,0,0,0,218,6,109,111,100,117,108,101,114,175,
     0,0,0,114,7,0,0,0,114,7,0,0,0,114,8,0,
     0,0,218,11,101,120,101,99,95,109,111,100,117,108,101,60,
-    3,0,0,115,14,0,0,0,12,2,8,1,6,1,4,1,
-    6,255,20,2,255,128,122,25,95,76,111,97,100,101,114,66,
+    3,0,0,115,14,0,0,0,12,2,8,1,4,1,8,1,
+    4,255,20,2,255,128,122,25,95,76,111,97,100,101,114,66,
     97,115,105,99,115,46,101,120,101,99,95,109,111,100,117,108,
     101,99,2,0,0,0,0,0,0,0,0,0,0,0,2,0,
     0,0,4,0,0,0,67,0,0,0,115,12,0,0,0,116,



More information about the Python-checkins mailing list