Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add orelse_lineno and orelse_col_offset to nodes.If #1480

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions astroid/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,25 @@ class BlockRangeMixIn:
def blockstart_tolineno(self):
return self.lineno

def _elsed_block_range(self, lineno, orelse, last=None):
def _elsed_block_range(
self, lineno: int, orelse: list[nodes.NodeNG], last: int | None = None
) -> tuple[int, int]:
"""handle block line numbers range for try/finally, for, if and while
statements
"""
if lineno == self.fromlineno:
# If at the end of the node, return same line
if lineno == self.tolineno:
return lineno, lineno
if orelse:
if lineno >= orelse[0].fromlineno:
# If the lineno is beyond the body of the node we check the orelse
if lineno >= self.body[-1].tolineno + 1:
# If the orelse has a scope of its own we determine the block range there
if isinstance(orelse[0], BlockRangeMixIn):
return orelse[0]._elsed_block_range(lineno, orelse[0].orelse)
# Return last line of orelse
return lineno, orelse[-1].tolineno
return lineno, orelse[0].fromlineno - 1
# If the lineno is within the body we take the last line of the body
return lineno, self.body[-1].tolineno
return lineno, last or self.tolineno


Expand Down
57 changes: 52 additions & 5 deletions tests/unittest_nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,11 +325,22 @@ class IfNodeTest(_NodeTest):
pass
else:
raise

if 1:
print()
elif (
2
and 3
):
print()
else:
# This is using else in a comment
raise
"""

def test_if_elif_else_node(self) -> None:
"""test transformation for If node"""
self.assertEqual(len(self.astroid.body), 4)
self.assertEqual(len(self.astroid.body), 5)
for stmt in self.astroid.body:
self.assertIsInstance(stmt, nodes.If)
self.assertFalse(self.astroid.body[0].orelse) # simple If
Expand All @@ -338,13 +349,49 @@ def test_if_elif_else_node(self) -> None:
self.assertIsInstance(self.astroid.body[3].orelse[0].orelse[0], nodes.If)

def test_block_range(self) -> None:
"""Test block_range of various scope constructs"""
# XXX ensure expected values
self.assertEqual(self.astroid.block_range(1), (0, 22))
self.assertEqual(self.astroid.block_range(10), (0, 22)) # XXX (10, 22) ?
# Module
self.assertEqual(self.astroid.block_range(1), (0, 33))
self.assertEqual(self.astroid.block_range(10), (0, 33)) # XXX (10, 33) ?

# if
self.assertEqual(self.astroid.body[0].block_range(2), (2, 3))
self.assertEqual(self.astroid.body[0].block_range(3), (3, 3))

# if ... else
self.assertEqual(self.astroid.body[1].block_range(5), (5, 6))
self.assertEqual(self.astroid.body[1].block_range(6), (6, 6))
self.assertEqual(self.astroid.body[1].orelse[0].block_range(7), (7, 8))
self.assertEqual(self.astroid.body[1].orelse[0].block_range(8), (8, 8))
self.assertEqual(self.astroid.body[1].block_range(7), (7, 8))
self.assertEqual(self.astroid.body[1].block_range(8), (8, 8))

# if ... elif
self.assertEqual(self.astroid.body[2].block_range(10), (10, 11))
self.assertEqual(self.astroid.body[2].block_range(11), (11, 11))
self.assertEqual(self.astroid.body[2].block_range(12), (12, 13))
self.assertEqual(self.astroid.body[2].block_range(13), (13, 13))

# if ... elif ... elif ... else
self.assertEqual(self.astroid.body[3].block_range(15), (15, 16))
self.assertEqual(self.astroid.body[3].block_range(16), (16, 16))
self.assertEqual(self.astroid.body[3].block_range(17), (17, 18))
self.assertEqual(self.astroid.body[3].block_range(18), (18, 18))
self.assertEqual(self.astroid.body[3].block_range(19), (19, 20))
self.assertEqual(self.astroid.body[3].block_range(20), (20, 20))
self.assertEqual(self.astroid.body[3].block_range(21), (21, 22))
self.assertEqual(self.astroid.body[3].block_range(22), (22, 22))

# if ... elif ... else
self.assertEqual(self.astroid.body[4].block_range(24), (24, 25))
self.assertEqual(self.astroid.body[4].block_range(25), (25, 25))
self.assertEqual(self.astroid.body[4].block_range(26), (26, 30))
self.assertEqual(self.astroid.body[4].block_range(27), (27, 30))
self.assertEqual(self.astroid.body[4].block_range(28), (28, 30))
self.assertEqual(self.astroid.body[4].block_range(29), (29, 30))
self.assertEqual(self.astroid.body[4].block_range(30), (30, 30))
self.assertEqual(self.astroid.body[4].block_range(31), (31, 33))
self.assertEqual(self.astroid.body[4].block_range(32), (32, 33))
self.assertEqual(self.astroid.body[4].block_range(33), (33, 33))

@staticmethod
@pytest.mark.filterwarnings("ignore:.*is_sys_guard:DeprecationWarning")
Expand Down