[Python-checkins] [3.8] bpo-40726: handle uninitalized end_lineno on ast.increment_lineno (GH-21745)

Batuhan Taskaya webhook-mailer at python.org
Wed Aug 5 14:37:28 EDT 2020


https://github.com/python/cpython/commit/b24c9d2b0656764bef48120d9511faf833bd7ead
commit: b24c9d2b0656764bef48120d9511faf833bd7ead
branch: 3.8
author: Batuhan Taskaya <batuhanosmantaskaya at gmail.com>
committer: GitHub <noreply at github.com>
date: 2020-08-05T11:37:19-07:00
summary:

[3.8] bpo-40726: handle uninitalized end_lineno on ast.increment_lineno (GH-21745)



…no (GH-20312).

(cherry picked from commit 8f4380d2f5839a321475104765221a7394a9d649)

Co-authored-by: Batuhan Taskaya <batuhanosmantaskaya at gmail.com>

Automerge-Triggered-By: @pablogsal

files:
A Misc/NEWS.d/next/Library/2020-05-22-12-45-58.bpo-40726.7oBdMw.rst
M Lib/ast.py
M Lib/test/test_ast.py

diff --git a/Lib/ast.py b/Lib/ast.py
index 99a1148a3ba24..d29db80a085fd 100644
--- a/Lib/ast.py
+++ b/Lib/ast.py
@@ -144,9 +144,14 @@ def copy_location(new_node, old_node):
     attributes) from *old_node* to *new_node* if possible, and return *new_node*.
     """
     for attr in 'lineno', 'col_offset', 'end_lineno', 'end_col_offset':
-        if attr in old_node._attributes and attr in new_node._attributes \
-           and hasattr(old_node, attr):
-            setattr(new_node, attr, getattr(old_node, attr))
+        if attr in old_node._attributes and attr in new_node._attributes:
+            value = getattr(old_node, attr, None)
+            # end_lineno and end_col_offset are optional attributes, and they
+            # should be copied whether the value is None or not.
+            if value is not None or (
+                hasattr(old_node, attr) and attr.startswith("end_")
+            ):
+                setattr(new_node, attr, value)
     return new_node
 
 
@@ -194,8 +199,11 @@ def increment_lineno(node, n=1):
     for child in walk(node):
         if 'lineno' in child._attributes:
             child.lineno = getattr(child, 'lineno', 0) + n
-        if 'end_lineno' in child._attributes:
-            child.end_lineno = getattr(child, 'end_lineno', 0) + n
+        if (
+            "end_lineno" in child._attributes
+            and (end_lineno := getattr(child, "end_lineno", 0)) is not None
+        ):
+            child.end_lineno = end_lineno + n
     return node
 
 
diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
index b921f4a5d6826..c625e693f50de 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -718,6 +718,15 @@ def test_copy_location(self):
             'lineno=1, col_offset=4, end_lineno=1, end_col_offset=5), lineno=1, '
             'col_offset=0, end_lineno=1, end_col_offset=5))'
         )
+        src = ast.Call(col_offset=1, lineno=1, end_lineno=1, end_col_offset=1)
+        new = ast.copy_location(src, ast.Call(
+            col_offset=None, lineno=None,
+            end_lineno=None, end_col_offset=None
+        ))
+        self.assertIsNone(new.end_lineno)
+        self.assertIsNone(new.end_col_offset)
+        self.assertEqual(new.lineno, 1)
+        self.assertEqual(new.col_offset, 1)
 
     def test_fix_missing_locations(self):
         src = ast.parse('write("spam")')
@@ -757,6 +766,12 @@ def test_increment_lineno(self):
             'lineno=4, col_offset=4, end_lineno=4, end_col_offset=5), lineno=4, '
             'col_offset=0, end_lineno=4, end_col_offset=5))'
         )
+        src = ast.Call(
+            func=ast.Name("test", ast.Load()), args=[], keywords=[],
+            lineno=1, end_lineno=None
+        )
+        self.assertEqual(ast.increment_lineno(src).lineno, 2)
+        self.assertIsNone(ast.increment_lineno(src).end_lineno)
 
     def test_iter_fields(self):
         node = ast.parse('foo()', mode='eval')
diff --git a/Misc/NEWS.d/next/Library/2020-05-22-12-45-58.bpo-40726.7oBdMw.rst b/Misc/NEWS.d/next/Library/2020-05-22-12-45-58.bpo-40726.7oBdMw.rst
new file mode 100644
index 0000000000000..7409eb3d80df6
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2020-05-22-12-45-58.bpo-40726.7oBdMw.rst
@@ -0,0 +1,2 @@
+Handle cases where the ``end_lineno`` is ``None`` on
+:func:`ast.increment_lineno`.



More information about the Python-checkins mailing list