Skip to content

Commit 64eaa29

Browse files
committed
[3.8] bpo-40726: handle uninitalized end_lineno on ast.increment_lineno (pythonGH-20312).
(cherry picked from commit 8f4380d) Co-authored-by: Batuhan Taskaya <[email protected]>
1 parent f0e030c commit 64eaa29

File tree

3 files changed

+30
-5
lines changed

3 files changed

+30
-5
lines changed

Lib/ast.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,14 @@ def copy_location(new_node, old_node):
144144
attributes) from *old_node* to *new_node* if possible, and return *new_node*.
145145
"""
146146
for attr in 'lineno', 'col_offset', 'end_lineno', 'end_col_offset':
147-
if attr in old_node._attributes and attr in new_node._attributes \
148-
and hasattr(old_node, attr):
149-
setattr(new_node, attr, getattr(old_node, attr))
147+
if attr in old_node._attributes and attr in new_node._attributes:
148+
value = getattr(old_node, attr, None)
149+
# end_lineno and end_col_offset are optional attributes, and they
150+
# should be copied whether the value is None or not.
151+
if value is not None or (
152+
hasattr(old_node, attr) and attr.startswith("end_")
153+
):
154+
setattr(new_node, attr, value)
150155
return new_node
151156

152157

@@ -194,8 +199,11 @@ def increment_lineno(node, n=1):
194199
for child in walk(node):
195200
if 'lineno' in child._attributes:
196201
child.lineno = getattr(child, 'lineno', 0) + n
197-
if 'end_lineno' in child._attributes:
198-
child.end_lineno = getattr(child, 'end_lineno', 0) + n
202+
if (
203+
"end_lineno" in child._attributes
204+
and (end_lineno := getattr(child, "end_lineno", 0)) is not None
205+
):
206+
child.end_lineno = end_lineno + n
199207
return node
200208

201209

Lib/test/test_ast.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,15 @@ def test_copy_location(self):
718718
'lineno=1, col_offset=4, end_lineno=1, end_col_offset=5), lineno=1, '
719719
'col_offset=0, end_lineno=1, end_col_offset=5))'
720720
)
721+
src = ast.Call(col_offset=1, lineno=1, end_lineno=1, end_col_offset=1)
722+
new = ast.copy_location(src, ast.Call(
723+
col_offset=None, lineno=None,
724+
end_lineno=None, end_col_offset=None
725+
))
726+
self.assertIsNone(new.end_lineno)
727+
self.assertIsNone(new.end_col_offset)
728+
self.assertEqual(new.lineno, 1)
729+
self.assertEqual(new.col_offset, 1)
721730

722731
def test_fix_missing_locations(self):
723732
src = ast.parse('write("spam")')
@@ -757,6 +766,12 @@ def test_increment_lineno(self):
757766
'lineno=4, col_offset=4, end_lineno=4, end_col_offset=5), lineno=4, '
758767
'col_offset=0, end_lineno=4, end_col_offset=5))'
759768
)
769+
src = ast.Call(
770+
func=ast.Name("test", ast.Load()), args=[], keywords=[],
771+
lineno=1, end_lineno=None
772+
)
773+
self.assertEqual(ast.increment_lineno(src).lineno, 2)
774+
self.assertIsNone(ast.increment_lineno(src).end_lineno)
760775

761776
def test_iter_fields(self):
762777
node = ast.parse('foo()', mode='eval')
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Handle cases where the ``end_lineno`` is ``None`` on
2+
:func:`ast.increment_lineno`.

0 commit comments

Comments
 (0)