forked from openkylin/astroid
1236 lines
53 KiB
Python
1236 lines
53 KiB
Python
import textwrap
|
|
|
|
import pytest
|
|
|
|
import astroid
|
|
from astroid import builder, nodes
|
|
from astroid.const import PY38_PLUS, PY39_PLUS, PY310_PLUS
|
|
|
|
|
|
@pytest.mark.skipif(
|
|
PY38_PLUS, reason="end_lineno and end_col_offset were added in PY38"
|
|
)
|
|
class TestEndLinenoNotSet:
|
|
"""Test 'end_lineno' and 'end_col_offset' are initialized as 'None' for Python < 3.8."""
|
|
|
|
@staticmethod
|
|
def test_end_lineno_not_set() -> None:
|
|
code = textwrap.dedent(
|
|
"""
|
|
[1, 2, 3] #@
|
|
var #@
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 2
|
|
|
|
n1 = ast_nodes[0]
|
|
assert isinstance(n1, nodes.List)
|
|
assert (n1.lineno, n1.col_offset) == (1, 0)
|
|
assert (n1.end_lineno, n1.end_col_offset) == (None, None)
|
|
|
|
n2 = ast_nodes[1]
|
|
assert isinstance(n2, nodes.Name)
|
|
assert (n2.lineno, n2.col_offset) == (2, 0)
|
|
assert (n2.end_lineno, n2.end_col_offset) == (None, None)
|
|
|
|
|
|
@pytest.mark.skipif(
|
|
not PY38_PLUS, reason="end_lineno and end_col_offset were added in PY38"
|
|
)
|
|
class TestLinenoColOffset:
|
|
"""Test 'lineno', 'col_offset', 'end_lineno', and 'end_col_offset' for all nodes."""
|
|
|
|
@staticmethod
|
|
def test_end_lineno_container() -> None:
|
|
"""Container nodes: List, Tuple, Set."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
[1, 2, 3] #@
|
|
[ #@
|
|
1, 2, 3
|
|
]
|
|
(1, 2, 3) #@
|
|
{1, 2, 3} #@
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 4
|
|
|
|
c1 = ast_nodes[0]
|
|
assert isinstance(c1, nodes.List)
|
|
assert (c1.lineno, c1.col_offset) == (1, 0)
|
|
assert (c1.end_lineno, c1.end_col_offset) == (1, 9)
|
|
|
|
c2 = ast_nodes[1]
|
|
assert isinstance(c2, nodes.List)
|
|
assert (c2.lineno, c2.col_offset) == (2, 0)
|
|
assert (c2.end_lineno, c2.end_col_offset) == (4, 1)
|
|
|
|
c3 = ast_nodes[2]
|
|
assert isinstance(c3, nodes.Tuple)
|
|
assert (c3.lineno, c3.col_offset) == (5, 0)
|
|
assert (c3.end_lineno, c3.end_col_offset) == (5, 9)
|
|
|
|
c4 = ast_nodes[3]
|
|
assert isinstance(c4, nodes.Set)
|
|
assert (c4.lineno, c4.col_offset) == (6, 0)
|
|
assert (c4.end_lineno, c4.end_col_offset) == (6, 9)
|
|
|
|
@staticmethod
|
|
def test_end_lineno_name() -> None:
|
|
"""Name, Assign, AssignName, Delete, DelName."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
var = 42 #@
|
|
var #@
|
|
del var #@
|
|
|
|
var2 = ( #@
|
|
1, 2, 3
|
|
)
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 4
|
|
|
|
n1 = ast_nodes[0]
|
|
assert isinstance(n1, nodes.Assign)
|
|
assert isinstance(n1.targets[0], nodes.AssignName)
|
|
assert isinstance(n1.value, nodes.Const)
|
|
assert (n1.lineno, n1.col_offset) == (1, 0)
|
|
assert (n1.end_lineno, n1.end_col_offset) == (1, 8)
|
|
assert (n1.targets[0].lineno, n1.targets[0].col_offset) == (1, 0)
|
|
assert (n1.targets[0].end_lineno, n1.targets[0].end_col_offset) == (1, 3)
|
|
assert (n1.value.lineno, n1.value.col_offset) == (1, 6)
|
|
assert (n1.value.end_lineno, n1.value.end_col_offset) == (1, 8)
|
|
|
|
n2 = ast_nodes[1]
|
|
assert isinstance(n2, nodes.Name)
|
|
assert (n2.lineno, n2.col_offset) == (2, 0)
|
|
assert (n2.end_lineno, n2.end_col_offset) == (2, 3)
|
|
|
|
n3 = ast_nodes[2]
|
|
assert isinstance(n3, nodes.Delete) and isinstance(n3.targets[0], nodes.DelName)
|
|
assert (n3.lineno, n3.col_offset) == (3, 0)
|
|
assert (n3.end_lineno, n3.end_col_offset) == (3, 7)
|
|
assert (n3.targets[0].lineno, n3.targets[0].col_offset) == (3, 4)
|
|
assert (n3.targets[0].end_lineno, n3.targets[0].end_col_offset) == (3, 7)
|
|
|
|
n4 = ast_nodes[3]
|
|
assert isinstance(n4, nodes.Assign)
|
|
assert isinstance(n4.targets[0], nodes.AssignName)
|
|
assert (n4.lineno, n4.col_offset) == (5, 0)
|
|
assert (n4.end_lineno, n4.end_col_offset) == (7, 1)
|
|
assert (n4.targets[0].lineno, n4.targets[0].col_offset) == (5, 0)
|
|
assert (n4.targets[0].end_lineno, n4.targets[0].end_col_offset) == (5, 4)
|
|
|
|
@staticmethod
|
|
def test_end_lineno_attribute() -> None:
|
|
"""Attribute, AssignAttr, DelAttr."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
class X:
|
|
var = 42
|
|
|
|
X.var2 = 2 #@
|
|
X.var2 #@
|
|
del X.var2 #@
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 3
|
|
|
|
a1 = ast_nodes[0]
|
|
assert isinstance(a1, nodes.Assign)
|
|
assert isinstance(a1.targets[0], nodes.AssignAttr)
|
|
assert isinstance(a1.value, nodes.Const)
|
|
assert (a1.lineno, a1.col_offset) == (4, 0)
|
|
assert (a1.end_lineno, a1.end_col_offset) == (4, 10)
|
|
assert (a1.targets[0].lineno, a1.targets[0].col_offset) == (4, 0)
|
|
assert (a1.targets[0].end_lineno, a1.targets[0].end_col_offset) == (4, 6)
|
|
assert (a1.value.lineno, a1.value.col_offset) == (4, 9)
|
|
assert (a1.value.end_lineno, a1.value.end_col_offset) == (4, 10)
|
|
|
|
a2 = ast_nodes[1]
|
|
assert isinstance(a2, nodes.Attribute) and isinstance(a2.expr, nodes.Name)
|
|
assert (a2.lineno, a2.col_offset) == (5, 0)
|
|
assert (a2.end_lineno, a2.end_col_offset) == (5, 6)
|
|
assert (a2.expr.lineno, a2.expr.col_offset) == (5, 0)
|
|
assert (a2.expr.end_lineno, a2.expr.end_col_offset) == (5, 1)
|
|
|
|
a3 = ast_nodes[2]
|
|
assert isinstance(a3, nodes.Delete) and isinstance(a3.targets[0], nodes.DelAttr)
|
|
assert (a3.lineno, a3.col_offset) == (6, 0)
|
|
assert (a3.end_lineno, a3.end_col_offset) == (6, 10)
|
|
assert (a3.targets[0].lineno, a3.targets[0].col_offset) == (6, 4)
|
|
assert (a3.targets[0].end_lineno, a3.targets[0].end_col_offset) == (6, 10)
|
|
|
|
@staticmethod
|
|
def test_end_lineno_call() -> None:
|
|
"""Call, Keyword."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
func(arg1, arg2=value) #@
|
|
"""
|
|
).strip()
|
|
c1 = builder.extract_node(code)
|
|
assert isinstance(c1, nodes.Call)
|
|
assert isinstance(c1.func, nodes.Name)
|
|
assert isinstance(c1.args[0], nodes.Name)
|
|
assert isinstance(c1.keywords[0], nodes.Keyword)
|
|
assert isinstance(c1.keywords[0].value, nodes.Name)
|
|
|
|
assert (c1.lineno, c1.col_offset) == (1, 0)
|
|
assert (c1.end_lineno, c1.end_col_offset) == (1, 22)
|
|
assert (c1.func.lineno, c1.func.col_offset) == (1, 0)
|
|
assert (c1.func.end_lineno, c1.func.end_col_offset) == (1, 4)
|
|
|
|
assert (c1.args[0].lineno, c1.args[0].col_offset) == (1, 5)
|
|
assert (c1.args[0].end_lineno, c1.args[0].end_col_offset) == (1, 9)
|
|
|
|
# fmt: off
|
|
if PY39_PLUS:
|
|
# 'lineno' and 'col_offset' information only added in Python 3.9
|
|
assert (c1.keywords[0].lineno, c1.keywords[0].col_offset) == (1, 11)
|
|
assert (c1.keywords[0].end_lineno, c1.keywords[0].end_col_offset) == (1, 21)
|
|
else:
|
|
assert (c1.keywords[0].lineno, c1.keywords[0].col_offset) == (None, None)
|
|
assert (c1.keywords[0].end_lineno, c1.keywords[0].end_col_offset) == (None, None)
|
|
assert (c1.keywords[0].value.lineno, c1.keywords[0].value.col_offset) == (1, 16)
|
|
assert (c1.keywords[0].value.end_lineno, c1.keywords[0].value.end_col_offset) == (1, 21)
|
|
# fmt: on
|
|
|
|
@staticmethod
|
|
def test_end_lineno_assignment() -> None:
|
|
"""Assign, AnnAssign, AugAssign."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
var = 2 #@
|
|
var2: int = 2 #@
|
|
var3 += 2 #@
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 3
|
|
|
|
a1 = ast_nodes[0]
|
|
assert isinstance(a1, nodes.Assign)
|
|
assert isinstance(a1.targets[0], nodes.AssignName)
|
|
assert isinstance(a1.value, nodes.Const)
|
|
assert (a1.lineno, a1.col_offset) == (1, 0)
|
|
assert (a1.end_lineno, a1.end_col_offset) == (1, 7)
|
|
assert (a1.targets[0].lineno, a1.targets[0].col_offset) == (1, 0)
|
|
assert (a1.targets[0].end_lineno, a1.targets[0].end_col_offset) == (1, 3)
|
|
assert (a1.value.lineno, a1.value.col_offset) == (1, 6)
|
|
assert (a1.value.end_lineno, a1.value.end_col_offset) == (1, 7)
|
|
|
|
a2 = ast_nodes[1]
|
|
assert isinstance(a2, nodes.AnnAssign)
|
|
assert isinstance(a2.target, nodes.AssignName)
|
|
assert isinstance(a2.annotation, nodes.Name)
|
|
assert isinstance(a2.value, nodes.Const)
|
|
assert (a2.lineno, a2.col_offset) == (2, 0)
|
|
assert (a2.end_lineno, a2.end_col_offset) == (2, 13)
|
|
assert (a2.target.lineno, a2.target.col_offset) == (2, 0)
|
|
assert (a2.target.end_lineno, a2.target.end_col_offset) == (2, 4)
|
|
assert (a2.annotation.lineno, a2.annotation.col_offset) == (2, 6)
|
|
assert (a2.annotation.end_lineno, a2.annotation.end_col_offset) == (2, 9)
|
|
assert (a2.value.lineno, a2.value.col_offset) == (2, 12)
|
|
assert (a2.value.end_lineno, a2.value.end_col_offset) == (2, 13)
|
|
|
|
a3 = ast_nodes[2]
|
|
assert isinstance(a3, nodes.AugAssign)
|
|
assert isinstance(a3.target, nodes.AssignName)
|
|
assert isinstance(a3.value, nodes.Const)
|
|
assert (a3.lineno, a3.col_offset) == (3, 0)
|
|
assert (a3.end_lineno, a3.end_col_offset) == (3, 9)
|
|
assert (a3.target.lineno, a3.target.col_offset) == (3, 0)
|
|
assert (a3.target.end_lineno, a3.target.end_col_offset) == (3, 4)
|
|
assert (a3.value.lineno, a3.value.col_offset) == (3, 8)
|
|
assert (a3.value.end_lineno, a3.value.end_col_offset) == (3, 9)
|
|
|
|
@staticmethod
|
|
def test_end_lineno_mix_stmts() -> None:
|
|
"""Assert, Break, Continue, Global, Nonlocal, Pass, Raise, Return, Expr."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
assert True, "Some message" #@
|
|
break #@
|
|
continue #@
|
|
global var #@
|
|
nonlocal var #@
|
|
pass #@
|
|
raise Exception from ex #@
|
|
return 42 #@
|
|
var #@
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 9
|
|
|
|
s1 = ast_nodes[0]
|
|
assert isinstance(s1, nodes.Assert)
|
|
assert isinstance(s1.test, nodes.Const)
|
|
assert isinstance(s1.fail, nodes.Const)
|
|
assert (s1.lineno, s1.col_offset) == (1, 0)
|
|
assert (s1.end_lineno, s1.end_col_offset) == (1, 27)
|
|
assert (s1.test.lineno, s1.test.col_offset) == (1, 7)
|
|
assert (s1.test.end_lineno, s1.test.end_col_offset) == (1, 11)
|
|
assert (s1.fail.lineno, s1.fail.col_offset) == (1, 13)
|
|
assert (s1.fail.end_lineno, s1.fail.end_col_offset) == (1, 27)
|
|
|
|
s2 = ast_nodes[1]
|
|
assert isinstance(s2, nodes.Break)
|
|
assert (s2.lineno, s2.col_offset) == (2, 0)
|
|
assert (s2.end_lineno, s2.end_col_offset) == (2, 5)
|
|
|
|
s3 = ast_nodes[2]
|
|
assert isinstance(s3, nodes.Continue)
|
|
assert (s3.lineno, s3.col_offset) == (3, 0)
|
|
assert (s3.end_lineno, s3.end_col_offset) == (3, 8)
|
|
|
|
s4 = ast_nodes[3]
|
|
assert isinstance(s4, nodes.Global)
|
|
assert (s4.lineno, s4.col_offset) == (4, 0)
|
|
assert (s4.end_lineno, s4.end_col_offset) == (4, 10)
|
|
|
|
s5 = ast_nodes[4]
|
|
assert isinstance(s5, nodes.Nonlocal)
|
|
assert (s5.lineno, s5.col_offset) == (5, 0)
|
|
assert (s5.end_lineno, s5.end_col_offset) == (5, 12)
|
|
|
|
s6 = ast_nodes[5]
|
|
assert isinstance(s6, nodes.Pass)
|
|
assert (s6.lineno, s6.col_offset) == (6, 0)
|
|
assert (s6.end_lineno, s6.end_col_offset) == (6, 4)
|
|
|
|
s7 = ast_nodes[6]
|
|
assert isinstance(s7, nodes.Raise)
|
|
assert isinstance(s7.exc, nodes.Name)
|
|
assert isinstance(s7.cause, nodes.Name)
|
|
assert (s7.lineno, s7.col_offset) == (7, 0)
|
|
assert (s7.end_lineno, s7.end_col_offset) == (7, 23)
|
|
assert (s7.exc.lineno, s7.exc.col_offset) == (7, 6)
|
|
assert (s7.exc.end_lineno, s7.exc.end_col_offset) == (7, 15)
|
|
assert (s7.cause.lineno, s7.cause.col_offset) == (7, 21)
|
|
assert (s7.cause.end_lineno, s7.cause.end_col_offset) == (7, 23)
|
|
|
|
s8 = ast_nodes[7]
|
|
assert isinstance(s8, nodes.Return)
|
|
assert isinstance(s8.value, nodes.Const)
|
|
assert (s8.lineno, s8.col_offset) == (8, 0)
|
|
assert (s8.end_lineno, s8.end_col_offset) == (8, 9)
|
|
assert (s8.value.lineno, s8.value.col_offset) == (8, 7)
|
|
assert (s8.value.end_lineno, s8.value.end_col_offset) == (8, 9)
|
|
|
|
s9 = ast_nodes[8].parent
|
|
assert isinstance(s9, nodes.Expr)
|
|
assert isinstance(s9.value, nodes.Name)
|
|
assert (s9.lineno, s9.col_offset) == (9, 0)
|
|
assert (s9.end_lineno, s9.end_col_offset) == (9, 3)
|
|
assert (s9.value.lineno, s9.value.col_offset) == (9, 0)
|
|
assert (s9.value.end_lineno, s9.value.end_col_offset) == (9, 3)
|
|
|
|
@staticmethod
|
|
def test_end_lineno_mix_nodes() -> None:
|
|
"""Await, Starred, Yield, YieldFrom."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
await func #@
|
|
*args #@
|
|
yield 42 #@
|
|
yield from (1, 2) #@
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 4
|
|
|
|
n1 = ast_nodes[0]
|
|
assert isinstance(n1, nodes.Await)
|
|
assert isinstance(n1.value, nodes.Name)
|
|
assert (n1.lineno, n1.col_offset) == (1, 0)
|
|
assert (n1.end_lineno, n1.end_col_offset) == (1, 10)
|
|
assert (n1.value.lineno, n1.value.col_offset) == (1, 6)
|
|
assert (n1.value.end_lineno, n1.value.end_col_offset) == (1, 10)
|
|
|
|
n2 = ast_nodes[1]
|
|
assert isinstance(n2, nodes.Starred)
|
|
assert isinstance(n2.value, nodes.Name)
|
|
assert (n2.lineno, n2.col_offset) == (2, 0)
|
|
assert (n2.end_lineno, n2.end_col_offset) == (2, 5)
|
|
assert (n2.value.lineno, n2.value.col_offset) == (2, 1)
|
|
assert (n2.value.end_lineno, n2.value.end_col_offset) == (2, 5)
|
|
|
|
n3 = ast_nodes[2]
|
|
assert isinstance(n3, nodes.Yield)
|
|
assert isinstance(n3.value, nodes.Const)
|
|
assert (n3.lineno, n3.col_offset) == (3, 0)
|
|
assert (n3.end_lineno, n3.end_col_offset) == (3, 8)
|
|
assert (n3.value.lineno, n3.value.col_offset) == (3, 6)
|
|
assert (n3.value.end_lineno, n3.value.end_col_offset) == (3, 8)
|
|
|
|
n4 = ast_nodes[3]
|
|
assert isinstance(n4, nodes.YieldFrom)
|
|
assert isinstance(n4.value, nodes.Tuple)
|
|
assert (n4.lineno, n4.col_offset) == (4, 0)
|
|
assert (n4.end_lineno, n4.end_col_offset) == (4, 17)
|
|
assert (n4.value.lineno, n4.value.col_offset) == (4, 11)
|
|
assert (n4.value.end_lineno, n4.value.end_col_offset) == (4, 17)
|
|
|
|
@staticmethod
|
|
def test_end_lineno_ops() -> None:
|
|
"""BinOp, BoolOp, UnaryOp, Compare."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
x + y #@
|
|
a and b #@
|
|
-var #@
|
|
a < b #@
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 4
|
|
|
|
o1 = ast_nodes[0]
|
|
assert isinstance(o1, nodes.BinOp)
|
|
assert isinstance(o1.left, nodes.Name)
|
|
assert isinstance(o1.right, nodes.Name)
|
|
assert (o1.lineno, o1.col_offset) == (1, 0)
|
|
assert (o1.end_lineno, o1.end_col_offset) == (1, 5)
|
|
assert (o1.left.lineno, o1.left.col_offset) == (1, 0)
|
|
assert (o1.left.end_lineno, o1.left.end_col_offset) == (1, 1)
|
|
assert (o1.right.lineno, o1.right.col_offset) == (1, 4)
|
|
assert (o1.right.end_lineno, o1.right.end_col_offset) == (1, 5)
|
|
|
|
o2 = ast_nodes[1]
|
|
assert isinstance(o2, nodes.BoolOp)
|
|
assert isinstance(o2.values[0], nodes.Name)
|
|
assert isinstance(o2.values[1], nodes.Name)
|
|
assert (o2.lineno, o2.col_offset) == (2, 0)
|
|
assert (o2.end_lineno, o2.end_col_offset) == (2, 7)
|
|
assert (o2.values[0].lineno, o2.values[0].col_offset) == (2, 0)
|
|
assert (o2.values[0].end_lineno, o2.values[0].end_col_offset) == (2, 1)
|
|
assert (o2.values[1].lineno, o2.values[1].col_offset) == (2, 6)
|
|
assert (o2.values[1].end_lineno, o2.values[1].end_col_offset) == (2, 7)
|
|
|
|
o3 = ast_nodes[2]
|
|
assert isinstance(o3, nodes.UnaryOp)
|
|
assert isinstance(o3.operand, nodes.Name)
|
|
assert (o3.lineno, o3.col_offset) == (3, 0)
|
|
assert (o3.end_lineno, o3.end_col_offset) == (3, 4)
|
|
assert (o3.operand.lineno, o3.operand.col_offset) == (3, 1)
|
|
assert (o3.operand.end_lineno, o3.operand.end_col_offset) == (3, 4)
|
|
|
|
o4 = ast_nodes[3]
|
|
assert isinstance(o4, nodes.Compare)
|
|
assert isinstance(o4.left, nodes.Name)
|
|
assert isinstance(o4.ops[0][1], nodes.Name)
|
|
assert (o4.lineno, o4.col_offset) == (4, 0)
|
|
assert (o4.end_lineno, o4.end_col_offset) == (4, 5)
|
|
assert (o4.left.lineno, o4.left.col_offset) == (4, 0)
|
|
assert (o4.left.end_lineno, o4.left.end_col_offset) == (4, 1)
|
|
assert (o4.ops[0][1].lineno, o4.ops[0][1].col_offset) == (4, 4)
|
|
assert (o4.ops[0][1].end_lineno, o4.ops[0][1].end_col_offset) == (4, 5)
|
|
|
|
@staticmethod
|
|
def test_end_lineno_if() -> None:
|
|
"""If, IfExp, NamedExpr."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
if ( #@
|
|
var := 2 #@
|
|
):
|
|
pass
|
|
else:
|
|
pass
|
|
|
|
2 if True else 1 #@
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 3
|
|
|
|
i1 = ast_nodes[0]
|
|
assert isinstance(i1, nodes.If)
|
|
assert isinstance(i1.test, nodes.NamedExpr)
|
|
assert isinstance(i1.body[0], nodes.Pass)
|
|
assert isinstance(i1.orelse[0], nodes.Pass)
|
|
assert (i1.lineno, i1.col_offset) == (1, 0)
|
|
assert (i1.end_lineno, i1.end_col_offset) == (6, 8)
|
|
assert (i1.test.lineno, i1.test.col_offset) == (2, 4)
|
|
assert (i1.test.end_lineno, i1.test.end_col_offset) == (2, 12)
|
|
assert (i1.body[0].lineno, i1.body[0].col_offset) == (4, 4)
|
|
assert (i1.body[0].end_lineno, i1.body[0].end_col_offset) == (4, 8)
|
|
assert (i1.orelse[0].lineno, i1.orelse[0].col_offset) == (6, 4)
|
|
assert (i1.orelse[0].end_lineno, i1.orelse[0].end_col_offset) == (6, 8)
|
|
|
|
i2 = ast_nodes[1]
|
|
assert isinstance(i2, nodes.NamedExpr)
|
|
assert isinstance(i2.target, nodes.AssignName)
|
|
assert isinstance(i2.value, nodes.Const)
|
|
assert (i2.lineno, i2.col_offset) == (2, 4)
|
|
assert (i2.end_lineno, i2.end_col_offset) == (2, 12)
|
|
assert (i2.target.lineno, i2.target.col_offset) == (2, 4)
|
|
assert (i2.target.end_lineno, i2.target.end_col_offset) == (2, 7)
|
|
assert (i2.value.lineno, i2.value.col_offset) == (2, 11)
|
|
assert (i2.value.end_lineno, i2.value.end_col_offset) == (2, 12)
|
|
|
|
i3 = ast_nodes[2]
|
|
assert isinstance(i3, nodes.IfExp)
|
|
assert isinstance(i3.test, nodes.Const)
|
|
assert isinstance(i3.body, nodes.Const)
|
|
assert isinstance(i3.orelse, nodes.Const)
|
|
assert (i3.lineno, i3.col_offset) == (8, 0)
|
|
assert (i3.end_lineno, i3.end_col_offset) == (8, 16)
|
|
assert (i3.test.lineno, i3.test.col_offset) == (8, 5)
|
|
assert (i3.test.end_lineno, i3.test.end_col_offset) == (8, 9)
|
|
assert (i3.body.lineno, i3.body.col_offset) == (8, 0)
|
|
assert (i3.body.end_lineno, i3.body.end_col_offset) == (8, 1)
|
|
assert (i3.orelse.lineno, i3.orelse.col_offset) == (8, 15)
|
|
assert (i3.orelse.end_lineno, i3.orelse.end_col_offset) == (8, 16)
|
|
|
|
@staticmethod
|
|
def test_end_lineno_for() -> None:
|
|
"""For, AsyncFor."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
for i in lst: #@
|
|
pass
|
|
else:
|
|
pass
|
|
|
|
async for i in lst: #@
|
|
pass
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 2
|
|
|
|
f1 = ast_nodes[0]
|
|
assert isinstance(f1, nodes.For)
|
|
assert isinstance(f1.target, nodes.AssignName)
|
|
assert isinstance(f1.iter, nodes.Name)
|
|
assert isinstance(f1.body[0], nodes.Pass)
|
|
assert isinstance(f1.orelse[0], nodes.Pass)
|
|
assert (f1.lineno, f1.col_offset) == (1, 0)
|
|
assert (f1.end_lineno, f1.end_col_offset) == (4, 8)
|
|
assert (f1.target.lineno, f1.target.col_offset) == (1, 4)
|
|
assert (f1.target.end_lineno, f1.target.end_col_offset) == (1, 5)
|
|
assert (f1.iter.lineno, f1.iter.col_offset) == (1, 9)
|
|
assert (f1.iter.end_lineno, f1.iter.end_col_offset) == (1, 12)
|
|
assert (f1.body[0].lineno, f1.body[0].col_offset) == (2, 4)
|
|
assert (f1.body[0].end_lineno, f1.body[0].end_col_offset) == (2, 8)
|
|
assert (f1.orelse[0].lineno, f1.orelse[0].col_offset) == (4, 4)
|
|
assert (f1.orelse[0].end_lineno, f1.orelse[0].end_col_offset) == (4, 8)
|
|
|
|
f2 = ast_nodes[1]
|
|
assert isinstance(f2, nodes.AsyncFor)
|
|
assert isinstance(f2.target, nodes.AssignName)
|
|
assert isinstance(f2.iter, nodes.Name)
|
|
assert isinstance(f2.body[0], nodes.Pass)
|
|
assert (f2.lineno, f2.col_offset) == (6, 0)
|
|
assert (f2.end_lineno, f2.end_col_offset) == (7, 8)
|
|
assert (f2.target.lineno, f2.target.col_offset) == (6, 10)
|
|
assert (f2.target.end_lineno, f2.target.end_col_offset) == (6, 11)
|
|
assert (f2.iter.lineno, f2.iter.col_offset) == (6, 15)
|
|
assert (f2.iter.end_lineno, f2.iter.end_col_offset) == (6, 18)
|
|
assert (f2.body[0].lineno, f2.body[0].col_offset) == (7, 4)
|
|
assert (f2.body[0].end_lineno, f2.body[0].end_col_offset) == (7, 8)
|
|
|
|
@staticmethod
|
|
def test_end_lineno_const() -> None:
|
|
"""Const (int, str, bool, None, bytes, ellipsis)."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
2 #@
|
|
"Hello" #@
|
|
True #@
|
|
None #@
|
|
b"01" #@
|
|
... #@
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 6
|
|
|
|
c1 = ast_nodes[0]
|
|
assert isinstance(c1, nodes.Const)
|
|
assert (c1.lineno, c1.col_offset) == (1, 0)
|
|
assert (c1.end_lineno, c1.end_col_offset) == (1, 1)
|
|
|
|
c2 = ast_nodes[1]
|
|
assert isinstance(c2, nodes.Const)
|
|
assert (c2.lineno, c2.col_offset) == (2, 0)
|
|
assert (c2.end_lineno, c2.end_col_offset) == (2, 7)
|
|
|
|
c3 = ast_nodes[2]
|
|
assert isinstance(c3, nodes.Const)
|
|
assert (c3.lineno, c3.col_offset) == (3, 0)
|
|
assert (c3.end_lineno, c3.end_col_offset) == (3, 4)
|
|
|
|
c4 = ast_nodes[3]
|
|
assert isinstance(c4, nodes.Const)
|
|
assert (c4.lineno, c4.col_offset) == (4, 0)
|
|
assert (c4.end_lineno, c4.end_col_offset) == (4, 4)
|
|
|
|
c5 = ast_nodes[4]
|
|
assert isinstance(c5, nodes.Const)
|
|
assert (c5.lineno, c5.col_offset) == (5, 0)
|
|
assert (c5.end_lineno, c5.end_col_offset) == (5, 5)
|
|
|
|
c6 = ast_nodes[5]
|
|
assert isinstance(c6, nodes.Const)
|
|
assert (c6.lineno, c6.col_offset) == (6, 0)
|
|
assert (c6.end_lineno, c6.end_col_offset) == (6, 3)
|
|
|
|
@staticmethod
|
|
def test_end_lineno_function() -> None:
|
|
"""FunctionDef, AsyncFunctionDef, Decorators, Lambda, Arguments."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
def func( #@
|
|
a: int = 0, /,
|
|
var: int = 1, *args: Any,
|
|
keyword: int = 2, **kwargs: Any
|
|
) -> None:
|
|
pass
|
|
|
|
@decorator1
|
|
@decorator2
|
|
async def func(): #@
|
|
pass
|
|
|
|
lambda x: 2 #@
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 3
|
|
|
|
# fmt: off
|
|
f1 = ast_nodes[0]
|
|
assert isinstance(f1, nodes.FunctionDef)
|
|
assert isinstance(f1.args, nodes.Arguments)
|
|
assert isinstance(f1.returns, nodes.Const)
|
|
assert isinstance(f1.body[0], nodes.Pass)
|
|
assert (f1.lineno, f1.col_offset) == (1, 0)
|
|
assert (f1.end_lineno, f1.end_col_offset) == (6, 8)
|
|
assert (f1.returns.lineno, f1.returns.col_offset) == (5, 5)
|
|
assert (f1.returns.end_lineno, f1.returns.end_col_offset) == (5, 9)
|
|
assert (f1.body[0].lineno, f1.body[0].col_offset) == (6, 4)
|
|
assert (f1.body[0].end_lineno, f1.body[0].end_col_offset) == (6, 8)
|
|
|
|
# pos only arguments
|
|
# TODO fix column offset: arg -> arg (AssignName)
|
|
assert isinstance(f1.args.posonlyargs[0], nodes.AssignName)
|
|
assert (f1.args.posonlyargs[0].lineno, f1.args.posonlyargs[0].col_offset) == (2, 4)
|
|
assert (f1.args.posonlyargs[0].end_lineno, f1.args.posonlyargs[0].end_col_offset) == (2, 10)
|
|
assert isinstance(f1.args.posonlyargs_annotations[0], nodes.Name)
|
|
assert (
|
|
f1.args.posonlyargs_annotations[0].lineno, f1.args.posonlyargs_annotations[0].col_offset
|
|
) == (2, 7)
|
|
assert (
|
|
f1.args.posonlyargs_annotations[0].end_lineno, f1.args.posonlyargs_annotations[0].end_col_offset
|
|
) == (2, 10)
|
|
assert (f1.args.defaults[0].lineno, f1.args.defaults[0].col_offset) == (2, 13)
|
|
assert (f1.args.defaults[0].end_lineno, f1.args.defaults[0].end_col_offset) == (2, 14)
|
|
|
|
# pos or kw arguments
|
|
assert isinstance(f1.args.args[0], nodes.AssignName)
|
|
assert (f1.args.args[0].lineno, f1.args.args[0].col_offset) == (3, 4)
|
|
assert (f1.args.args[0].end_lineno, f1.args.args[0].end_col_offset) == (3, 12)
|
|
assert isinstance(f1.args.annotations[0], nodes.Name)
|
|
assert (f1.args.annotations[0].lineno, f1.args.annotations[0].col_offset) == (3, 9)
|
|
assert (f1.args.annotations[0].end_lineno, f1.args.annotations[0].end_col_offset) == (3, 12)
|
|
assert isinstance(f1.args.defaults[1], nodes.Const)
|
|
assert (f1.args.defaults[1].lineno, f1.args.defaults[1].col_offset) == (3, 15)
|
|
assert (f1.args.defaults[1].end_lineno, f1.args.defaults[1].end_col_offset) == (3, 16)
|
|
|
|
# *args
|
|
assert isinstance(f1.args.varargannotation, nodes.Name)
|
|
assert (f1.args.varargannotation.lineno, f1.args.varargannotation.col_offset) == (3, 25)
|
|
assert (f1.args.varargannotation.end_lineno, f1.args.varargannotation.end_col_offset) == (3, 28)
|
|
|
|
# kw_only arguments
|
|
assert isinstance(f1.args.kwonlyargs[0], nodes.AssignName)
|
|
assert (f1.args.kwonlyargs[0].lineno, f1.args.kwonlyargs[0].col_offset) == (4, 4)
|
|
assert (f1.args.kwonlyargs[0].end_lineno, f1.args.kwonlyargs[0].end_col_offset) == (4, 16)
|
|
assert isinstance(f1.args.kwonlyargs_annotations[0], nodes.Name)
|
|
assert (f1.args.kwonlyargs_annotations[0].lineno, f1.args.kwonlyargs_annotations[0].col_offset) == (4, 13)
|
|
assert (f1.args.kwonlyargs_annotations[0].end_lineno, f1.args.kwonlyargs_annotations[0].end_col_offset) == (4, 16)
|
|
assert isinstance(f1.args.kw_defaults[0], nodes.Const)
|
|
assert (f1.args.kw_defaults[0].lineno, f1.args.kw_defaults[0].col_offset) == (4, 19)
|
|
assert (f1.args.kw_defaults[0].end_lineno, f1.args.kw_defaults[0].end_col_offset) == (4, 20)
|
|
|
|
# **kwargs
|
|
assert isinstance(f1.args.kwargannotation, nodes.Name)
|
|
assert (f1.args.kwargannotation.lineno, f1.args.kwargannotation.col_offset) == (4, 32)
|
|
assert (f1.args.kwargannotation.end_lineno, f1.args.kwargannotation.end_col_offset) == (4, 35)
|
|
|
|
f2 = ast_nodes[1]
|
|
assert isinstance(f2, nodes.AsyncFunctionDef)
|
|
assert isinstance(f2.decorators, nodes.Decorators)
|
|
assert isinstance(f2.decorators.nodes[0], nodes.Name)
|
|
assert isinstance(f2.decorators.nodes[1], nodes.Name)
|
|
assert (f2.lineno, f2.col_offset) == (8, 0)
|
|
assert (f2.end_lineno, f2.end_col_offset) == (11, 8)
|
|
assert (f2.decorators.lineno, f2.decorators.col_offset) == (8, 0)
|
|
assert (f2.decorators.end_lineno, f2.decorators.end_col_offset) == (9, 11)
|
|
assert (f2.decorators.nodes[0].lineno, f2.decorators.nodes[0].col_offset) == (8, 1)
|
|
assert (f2.decorators.nodes[0].end_lineno, f2.decorators.nodes[0].end_col_offset) == (8, 11)
|
|
assert (f2.decorators.nodes[1].lineno, f2.decorators.nodes[1].col_offset) == (9, 1)
|
|
assert (f2.decorators.nodes[1].end_lineno, f2.decorators.nodes[1].end_col_offset) == (9, 11)
|
|
|
|
f3 = ast_nodes[2]
|
|
assert isinstance(f3, nodes.Lambda)
|
|
assert isinstance(f3.args, nodes.Arguments)
|
|
assert isinstance(f3.args.args[0], nodes.AssignName)
|
|
assert isinstance(f3.body, nodes.Const)
|
|
assert (f3.lineno, f3.col_offset) == (13, 0)
|
|
assert (f3.end_lineno, f3.end_col_offset) == (13, 11)
|
|
assert (f3.args.args[0].lineno, f3.args.args[0].col_offset) == (13, 7)
|
|
assert (f3.args.args[0].end_lineno, f3.args.args[0].end_col_offset) == (13, 8)
|
|
assert (f3.body.lineno, f3.body.col_offset) == (13, 10)
|
|
assert (f3.body.end_lineno, f3.body.end_col_offset) == (13, 11)
|
|
# fmt: on
|
|
|
|
@staticmethod
|
|
def test_end_lineno_dict() -> None:
|
|
"""Dict, DictUnpack."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
{ #@
|
|
1: "Hello",
|
|
**{2: "World"} #@
|
|
}
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 2
|
|
|
|
d1 = ast_nodes[0]
|
|
assert isinstance(d1, nodes.Dict)
|
|
assert isinstance(d1.items[0][0], nodes.Const)
|
|
assert isinstance(d1.items[0][1], nodes.Const)
|
|
assert (d1.lineno, d1.col_offset) == (1, 0)
|
|
assert (d1.end_lineno, d1.end_col_offset) == (4, 1)
|
|
assert (d1.items[0][0].lineno, d1.items[0][0].col_offset) == (2, 4)
|
|
assert (d1.items[0][0].end_lineno, d1.items[0][0].end_col_offset) == (2, 5)
|
|
assert (d1.items[0][1].lineno, d1.items[0][1].col_offset) == (2, 7)
|
|
assert (d1.items[0][1].end_lineno, d1.items[0][1].end_col_offset) == (2, 14)
|
|
|
|
d2 = ast_nodes[1]
|
|
assert isinstance(d2, nodes.DictUnpack)
|
|
assert (d2.lineno, d2.col_offset) == (3, 6)
|
|
assert (d2.end_lineno, d2.end_col_offset) == (3, 18)
|
|
|
|
@staticmethod
|
|
def test_end_lineno_try() -> None:
|
|
"""TryExcept, TryFinally, ExceptHandler."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
try: #@
|
|
pass
|
|
except KeyError as ex:
|
|
pass
|
|
except AttributeError as ex:
|
|
pass
|
|
else:
|
|
pass
|
|
|
|
try: #@
|
|
pass
|
|
except KeyError as ex:
|
|
pass
|
|
else:
|
|
pass
|
|
finally:
|
|
pass
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 2
|
|
|
|
t1 = ast_nodes[0]
|
|
assert isinstance(t1, nodes.TryExcept)
|
|
assert isinstance(t1.body[0], nodes.Pass)
|
|
assert isinstance(t1.orelse[0], nodes.Pass)
|
|
assert (t1.lineno, t1.col_offset) == (1, 0)
|
|
assert (t1.end_lineno, t1.end_col_offset) == (8, 8)
|
|
assert (t1.body[0].lineno, t1.body[0].col_offset) == (2, 4)
|
|
assert (t1.body[0].end_lineno, t1.body[0].end_col_offset) == (2, 8)
|
|
assert (t1.orelse[0].lineno, t1.orelse[0].col_offset) == (8, 4)
|
|
assert (t1.orelse[0].end_lineno, t1.orelse[0].end_col_offset) == (8, 8)
|
|
|
|
t2 = t1.handlers[0]
|
|
assert isinstance(t2, nodes.ExceptHandler)
|
|
assert isinstance(t2.type, nodes.Name)
|
|
assert isinstance(t2.name, nodes.AssignName)
|
|
assert isinstance(t2.body[0], nodes.Pass)
|
|
assert (t2.lineno, t2.col_offset) == (3, 0)
|
|
assert (t2.end_lineno, t2.end_col_offset) == (4, 8)
|
|
assert (t2.type.lineno, t2.type.col_offset) == (3, 7)
|
|
assert (t2.type.end_lineno, t2.type.end_col_offset) == (3, 15)
|
|
# TODO fix column offset: ExceptHandler -> name (AssignName)
|
|
assert (t2.name.lineno, t2.name.col_offset) == (3, 0)
|
|
assert (t2.name.end_lineno, t2.name.end_col_offset) == (4, 8)
|
|
assert (t2.body[0].lineno, t2.body[0].col_offset) == (4, 4)
|
|
assert (t2.body[0].end_lineno, t2.body[0].end_col_offset) == (4, 8)
|
|
|
|
t3 = ast_nodes[1]
|
|
assert isinstance(t3, nodes.TryFinally)
|
|
assert isinstance(t3.body[0], nodes.TryExcept)
|
|
assert isinstance(t3.finalbody[0], nodes.Pass)
|
|
assert (t3.lineno, t3.col_offset) == (10, 0)
|
|
assert (t3.end_lineno, t3.end_col_offset) == (17, 8)
|
|
assert (t3.body[0].lineno, t3.body[0].col_offset) == (10, 0)
|
|
assert (t3.body[0].end_lineno, t3.body[0].end_col_offset) == (17, 8)
|
|
assert (t3.finalbody[0].lineno, t3.finalbody[0].col_offset) == (17, 4)
|
|
assert (t3.finalbody[0].end_lineno, t3.finalbody[0].end_col_offset) == (17, 8)
|
|
|
|
@staticmethod
|
|
def test_end_lineno_subscript() -> None:
|
|
"""Subscript, Slice, (ExtSlice, Index)."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
var[0] #@
|
|
var[1:2:1] #@
|
|
var[1:2, 2] #@
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 3
|
|
|
|
s1 = ast_nodes[0]
|
|
assert isinstance(s1, nodes.Subscript)
|
|
assert isinstance(s1.value, nodes.Name)
|
|
assert isinstance(s1.slice, nodes.Const)
|
|
assert (s1.lineno, s1.col_offset) == (1, 0)
|
|
assert (s1.end_lineno, s1.end_col_offset) == (1, 6)
|
|
assert (s1.value.lineno, s1.value.col_offset) == (1, 0)
|
|
assert (s1.value.end_lineno, s1.value.end_col_offset) == (1, 3)
|
|
assert (s1.slice.lineno, s1.slice.col_offset) == (1, 4)
|
|
assert (s1.slice.end_lineno, s1.slice.end_col_offset) == (1, 5)
|
|
|
|
s2 = ast_nodes[1]
|
|
assert isinstance(s2, nodes.Subscript)
|
|
assert isinstance(s2.slice, nodes.Slice)
|
|
assert isinstance(s2.slice.lower, nodes.Const)
|
|
assert isinstance(s2.slice.upper, nodes.Const)
|
|
assert isinstance(s2.slice.step, nodes.Const)
|
|
assert (s2.lineno, s2.col_offset) == (2, 0)
|
|
assert (s2.end_lineno, s2.end_col_offset) == (2, 10)
|
|
assert (s2.slice.lower.lineno, s2.slice.lower.col_offset) == (2, 4)
|
|
assert (s2.slice.lower.end_lineno, s2.slice.lower.end_col_offset) == (2, 5)
|
|
assert (s2.slice.upper.lineno, s2.slice.upper.col_offset) == (2, 6)
|
|
assert (s2.slice.upper.end_lineno, s2.slice.upper.end_col_offset) == (2, 7)
|
|
assert (s2.slice.step.lineno, s2.slice.step.col_offset) == (2, 8)
|
|
assert (s2.slice.step.end_lineno, s2.slice.step.end_col_offset) == (2, 9)
|
|
|
|
s3 = ast_nodes[2]
|
|
assert isinstance(s3, nodes.Subscript)
|
|
assert isinstance(s3.slice, nodes.Tuple)
|
|
assert (s3.lineno, s3.col_offset) == (3, 0)
|
|
assert (s3.end_lineno, s3.end_col_offset) == (3, 11)
|
|
if PY39_PLUS:
|
|
# 'lineno' and 'col_offset' information only added in Python 3.9
|
|
assert (s3.slice.lineno, s3.slice.col_offset) == (3, 4)
|
|
assert (s3.slice.end_lineno, s3.slice.end_col_offset) == (3, 10)
|
|
else:
|
|
assert (s3.slice.lineno, s3.slice.col_offset) == (None, None)
|
|
assert (s3.slice.end_lineno, s3.slice.end_col_offset) == (None, None)
|
|
|
|
@staticmethod
|
|
def test_end_lineno_import() -> None:
|
|
"""Import, ImportFrom."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
import a.b #@
|
|
import a as x #@
|
|
from . import x #@
|
|
from .a import y as y #@
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 4
|
|
|
|
i1 = ast_nodes[0]
|
|
assert isinstance(i1, nodes.Import)
|
|
assert (i1.lineno, i1.col_offset) == (1, 0)
|
|
assert (i1.end_lineno, i1.end_col_offset) == (1, 10)
|
|
|
|
i2 = ast_nodes[1]
|
|
assert isinstance(i2, nodes.Import)
|
|
assert (i2.lineno, i2.col_offset) == (2, 0)
|
|
assert (i2.end_lineno, i2.end_col_offset) == (2, 13)
|
|
|
|
i3 = ast_nodes[2]
|
|
assert isinstance(i3, nodes.ImportFrom)
|
|
assert (i3.lineno, i3.col_offset) == (3, 0)
|
|
assert (i3.end_lineno, i3.end_col_offset) == (3, 15)
|
|
|
|
i4 = ast_nodes[3]
|
|
assert isinstance(i4, nodes.ImportFrom)
|
|
assert (i4.lineno, i4.col_offset) == (4, 0)
|
|
assert (i4.end_lineno, i4.end_col_offset) == (4, 21)
|
|
|
|
@staticmethod
|
|
def test_end_lineno_with() -> None:
|
|
"""With, AsyncWith."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
with open(file) as fp, \\
|
|
open(file2) as fp2: #@
|
|
pass
|
|
|
|
async with open(file) as fp: #@
|
|
pass
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 2
|
|
|
|
w1 = ast_nodes[0].parent
|
|
assert isinstance(w1, nodes.With)
|
|
assert isinstance(w1.items[0][0], nodes.Call)
|
|
assert isinstance(w1.items[0][1], nodes.AssignName)
|
|
assert isinstance(w1.items[1][0], nodes.Call)
|
|
assert isinstance(w1.items[1][1], nodes.AssignName)
|
|
assert isinstance(w1.body[0], nodes.Pass)
|
|
assert (w1.lineno, w1.col_offset) == (1, 0)
|
|
assert (w1.end_lineno, w1.end_col_offset) == (3, 8)
|
|
assert (w1.items[0][0].lineno, w1.items[0][0].col_offset) == (1, 5)
|
|
assert (w1.items[0][0].end_lineno, w1.items[0][0].end_col_offset) == (1, 15)
|
|
assert (w1.items[0][1].lineno, w1.items[0][1].col_offset) == (1, 19)
|
|
assert (w1.items[0][1].end_lineno, w1.items[0][1].end_col_offset) == (1, 21)
|
|
assert (w1.items[1][0].lineno, w1.items[1][0].col_offset) == (2, 8)
|
|
assert (w1.items[1][0].end_lineno, w1.items[1][0].end_col_offset) == (2, 19)
|
|
assert (w1.items[1][1].lineno, w1.items[1][1].col_offset) == (2, 23)
|
|
assert (w1.items[1][1].end_lineno, w1.items[1][1].end_col_offset) == (2, 26)
|
|
assert (w1.body[0].lineno, w1.body[0].col_offset) == (3, 4)
|
|
assert (w1.body[0].end_lineno, w1.body[0].end_col_offset) == (3, 8)
|
|
|
|
w2 = ast_nodes[1]
|
|
assert isinstance(w2, nodes.AsyncWith)
|
|
assert isinstance(w2.items[0][0], nodes.Call)
|
|
assert isinstance(w2.items[0][1], nodes.AssignName)
|
|
assert isinstance(w2.body[0], nodes.Pass)
|
|
assert (w2.lineno, w2.col_offset) == (5, 0)
|
|
assert (w2.end_lineno, w2.end_col_offset) == (6, 8)
|
|
assert (w2.items[0][0].lineno, w2.items[0][0].col_offset) == (5, 11)
|
|
assert (w2.items[0][0].end_lineno, w2.items[0][0].end_col_offset) == (5, 21)
|
|
assert (w2.items[0][1].lineno, w2.items[0][1].col_offset) == (5, 25)
|
|
assert (w2.items[0][1].end_lineno, w2.items[0][1].end_col_offset) == (5, 27)
|
|
assert (w2.body[0].lineno, w2.body[0].col_offset) == (6, 4)
|
|
assert (w2.body[0].end_lineno, w2.body[0].end_col_offset) == (6, 8)
|
|
|
|
@staticmethod
|
|
def test_end_lineno_while() -> None:
|
|
"""While."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
while 2:
|
|
pass
|
|
else:
|
|
pass
|
|
"""
|
|
).strip()
|
|
w1 = builder.extract_node(code)
|
|
assert isinstance(w1, nodes.While)
|
|
assert isinstance(w1.test, nodes.Const)
|
|
assert isinstance(w1.body[0], nodes.Pass)
|
|
assert isinstance(w1.orelse[0], nodes.Pass)
|
|
assert (w1.lineno, w1.col_offset) == (1, 0)
|
|
assert (w1.end_lineno, w1.end_col_offset) == (4, 8)
|
|
assert (w1.test.lineno, w1.test.col_offset) == (1, 6)
|
|
assert (w1.test.end_lineno, w1.test.end_col_offset) == (1, 7)
|
|
assert (w1.body[0].lineno, w1.body[0].col_offset) == (2, 4)
|
|
assert (w1.body[0].end_lineno, w1.body[0].end_col_offset) == (2, 8)
|
|
assert (w1.orelse[0].lineno, w1.orelse[0].col_offset) == (4, 4)
|
|
assert (w1.orelse[0].end_lineno, w1.orelse[0].end_col_offset) == (4, 8)
|
|
|
|
@staticmethod
|
|
def test_end_lineno_string() -> None:
|
|
"""FormattedValue, JoinedStr."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
f"Hello World: {42.1234:02d}" #@
|
|
f"Hello: {name=}" #@
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 2
|
|
|
|
s1 = ast_nodes[0]
|
|
assert isinstance(s1, nodes.JoinedStr)
|
|
assert isinstance(s1.values[0], nodes.Const)
|
|
assert (s1.lineno, s1.col_offset) == (1, 0)
|
|
assert (s1.end_lineno, s1.end_col_offset) == (1, 29)
|
|
assert (s1.values[0].lineno, s1.values[0].col_offset) == (1, 0)
|
|
assert (s1.values[0].end_lineno, s1.values[0].end_col_offset) == (1, 29)
|
|
|
|
s2 = s1.values[1]
|
|
assert isinstance(s2, nodes.FormattedValue)
|
|
assert (s2.lineno, s2.col_offset) == (1, 0)
|
|
assert (s2.end_lineno, s2.end_col_offset) == (1, 29)
|
|
assert isinstance(s2.value, nodes.Const) # 42.1234
|
|
if PY39_PLUS:
|
|
assert (s2.value.lineno, s2.value.col_offset) == (1, 16)
|
|
assert (s2.value.end_lineno, s2.value.end_col_offset) == (1, 23)
|
|
else:
|
|
# Bug in Python 3.8
|
|
# https://bugs.python.org/issue44885
|
|
assert (s2.value.lineno, s2.value.col_offset) == (1, 1)
|
|
assert (s2.value.end_lineno, s2.value.end_col_offset) == (1, 8)
|
|
assert isinstance(s2.format_spec, nodes.JoinedStr) # '02d'
|
|
assert (s2.format_spec.lineno, s2.format_spec.col_offset) == (1, 0)
|
|
assert (s2.format_spec.end_lineno, s2.format_spec.end_col_offset) == (1, 29)
|
|
|
|
s3 = ast_nodes[1]
|
|
assert isinstance(s3, nodes.JoinedStr)
|
|
assert isinstance(s3.values[0], nodes.Const)
|
|
assert (s3.lineno, s3.col_offset) == (2, 0)
|
|
assert (s3.end_lineno, s3.end_col_offset) == (2, 17)
|
|
assert (s3.values[0].lineno, s3.values[0].col_offset) == (2, 0)
|
|
assert (s3.values[0].end_lineno, s3.values[0].end_col_offset) == (2, 17)
|
|
|
|
s4 = s3.values[1]
|
|
assert isinstance(s4, nodes.FormattedValue)
|
|
assert (s4.lineno, s4.col_offset) == (2, 0)
|
|
assert (s4.end_lineno, s4.end_col_offset) == (2, 17)
|
|
assert isinstance(s4.value, nodes.Name) # 'name'
|
|
if PY39_PLUS:
|
|
assert (s4.value.lineno, s4.value.col_offset) == (2, 10)
|
|
assert (s4.value.end_lineno, s4.value.end_col_offset) == (2, 14)
|
|
else:
|
|
# Bug in Python 3.8
|
|
# https://bugs.python.org/issue44885
|
|
assert (s4.value.lineno, s4.value.col_offset) == (2, 1)
|
|
assert (s4.value.end_lineno, s4.value.end_col_offset) == (2, 5)
|
|
|
|
@staticmethod
|
|
@pytest.mark.skipif(not PY310_PLUS, reason="pattern matching was added in PY310")
|
|
def test_end_lineno_match() -> None:
|
|
"""Match, MatchValue, MatchSingleton, MatchSequence, MatchMapping,
|
|
MatchClass, MatchStar, MatchOr, MatchAs.
|
|
"""
|
|
code = textwrap.dedent(
|
|
"""
|
|
match x: #@
|
|
case 200 if True: #@
|
|
pass
|
|
case True: #@
|
|
pass
|
|
case (1, 2, *args): #@
|
|
pass
|
|
case {1: "Hello", **rest}: #@
|
|
pass
|
|
case Point2d(0, y=0): #@
|
|
pass
|
|
case 200 | 300: #@
|
|
pass
|
|
case 200 as c: #@
|
|
pass
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 8
|
|
|
|
# fmt: off
|
|
m1 = ast_nodes[0]
|
|
assert isinstance(m1, nodes.Match)
|
|
assert (m1.lineno, m1.col_offset) == (1, 0)
|
|
assert (m1.end_lineno, m1.end_col_offset) == (15, 12)
|
|
assert (m1.subject.lineno, m1.subject.col_offset) == (1, 6)
|
|
assert (m1.subject.end_lineno, m1.subject.end_col_offset) == (1, 7)
|
|
|
|
m2 = ast_nodes[1]
|
|
assert isinstance(m2, nodes.MatchCase)
|
|
assert isinstance(m2.pattern, nodes.MatchValue)
|
|
assert isinstance(m2.guard, nodes.Const)
|
|
assert isinstance(m2.body[0], nodes.Pass)
|
|
assert (m2.pattern.lineno, m2.pattern.col_offset) == (2, 9)
|
|
assert (m2.pattern.end_lineno, m2.pattern.end_col_offset) == (2, 12)
|
|
assert (m2.guard.lineno, m2.guard.col_offset) == (2, 16)
|
|
assert (m2.guard.end_lineno, m2.guard.end_col_offset) == (2, 20)
|
|
assert (m2.body[0].lineno, m2.body[0].col_offset) == (3, 8)
|
|
assert (m2.body[0].end_lineno, m2.body[0].end_col_offset) == (3, 12)
|
|
|
|
m3 = ast_nodes[2]
|
|
assert isinstance(m3, nodes.MatchCase)
|
|
assert isinstance(m3.pattern, nodes.MatchSingleton)
|
|
assert (m3.pattern.lineno, m3.pattern.col_offset) == (4, 9)
|
|
assert (m3.pattern.end_lineno, m3.pattern.end_col_offset) == (4, 13)
|
|
|
|
m4 = ast_nodes[3]
|
|
assert isinstance(m4, nodes.MatchCase)
|
|
assert isinstance(m4.pattern, nodes.MatchSequence)
|
|
assert isinstance(m4.pattern.patterns[0], nodes.MatchValue)
|
|
assert (m4.pattern.lineno, m4.pattern.col_offset) == (6, 9)
|
|
assert (m4.pattern.end_lineno, m4.pattern.end_col_offset) == (6, 22)
|
|
assert (m4.pattern.patterns[0].lineno, m4.pattern.patterns[0].col_offset) == (6, 10)
|
|
assert (m4.pattern.patterns[0].end_lineno, m4.pattern.patterns[0].end_col_offset) == (6, 11)
|
|
|
|
m5 = m4.pattern.patterns[2]
|
|
assert isinstance(m5, nodes.MatchStar)
|
|
assert isinstance(m5.name, nodes.AssignName)
|
|
assert (m5.lineno, m5.col_offset) == (6, 16)
|
|
assert (m5.end_lineno, m5.end_col_offset) == (6, 21)
|
|
# TODO fix column offset: MatchStar -> name (AssignName)
|
|
assert (m5.name.lineno, m5.name.col_offset) == (6, 16)
|
|
assert (m5.name.end_lineno, m5.name.end_col_offset) == (6, 21)
|
|
|
|
m6 = ast_nodes[4]
|
|
assert isinstance(m6, nodes.MatchCase)
|
|
assert isinstance(m6.pattern, nodes.MatchMapping)
|
|
assert isinstance(m6.pattern.keys[0], nodes.Const)
|
|
assert isinstance(m6.pattern.patterns[0], nodes.MatchValue)
|
|
assert isinstance(m6.pattern.rest, nodes.AssignName)
|
|
assert (m6.pattern.lineno, m6.pattern.col_offset) == (8, 9)
|
|
assert (m6.pattern.end_lineno, m6.pattern.end_col_offset) == (8, 29)
|
|
assert (m6.pattern.keys[0].lineno, m6.pattern.keys[0].col_offset) == (8, 10)
|
|
assert (m6.pattern.keys[0].end_lineno, m6.pattern.keys[0].end_col_offset) == (8, 11)
|
|
assert (m6.pattern.patterns[0].lineno, m6.pattern.patterns[0].col_offset) == (8, 13)
|
|
assert (m6.pattern.patterns[0].end_lineno, m6.pattern.patterns[0].end_col_offset) == (8, 20)
|
|
# TODO fix column offset: MatchMapping -> rest (AssignName)
|
|
assert (m6.pattern.rest.lineno, m6.pattern.rest.col_offset) == (8, 9)
|
|
assert (m6.pattern.rest.end_lineno, m6.pattern.rest.end_col_offset) == (8, 29)
|
|
|
|
m7 = ast_nodes[5]
|
|
assert isinstance(m7, nodes.MatchCase)
|
|
assert isinstance(m7.pattern, nodes.MatchClass)
|
|
assert isinstance(m7.pattern.cls, nodes.Name)
|
|
assert isinstance(m7.pattern.patterns[0], nodes.MatchValue)
|
|
assert isinstance(m7.pattern.kwd_patterns[0], nodes.MatchValue)
|
|
assert (m7.pattern.lineno, m7.pattern.col_offset) == (10, 9)
|
|
assert (m7.pattern.end_lineno, m7.pattern.end_col_offset) == (10, 24)
|
|
assert (m7.pattern.cls.lineno, m7.pattern.cls.col_offset) == (10, 9)
|
|
assert (m7.pattern.cls.end_lineno, m7.pattern.cls.end_col_offset) == (10, 16)
|
|
assert (m7.pattern.patterns[0].lineno, m7.pattern.patterns[0].col_offset) == (10, 17)
|
|
assert (m7.pattern.patterns[0].end_lineno, m7.pattern.patterns[0].end_col_offset) == (10, 18)
|
|
assert (m7.pattern.kwd_patterns[0].lineno, m7.pattern.kwd_patterns[0].col_offset) == (10, 22)
|
|
assert (m7.pattern.kwd_patterns[0].end_lineno, m7.pattern.kwd_patterns[0].end_col_offset) == (10, 23)
|
|
|
|
m8 = ast_nodes[6]
|
|
assert isinstance(m8, nodes.MatchCase)
|
|
assert isinstance(m8.pattern, nodes.MatchOr)
|
|
assert isinstance(m8.pattern.patterns[0], nodes.MatchValue)
|
|
assert (m8.pattern.lineno, m8.pattern.col_offset) == (12, 9)
|
|
assert (m8.pattern.end_lineno, m8.pattern.end_col_offset) == (12, 18)
|
|
assert (m8.pattern.patterns[0].lineno, m8.pattern.patterns[0].col_offset) == (12, 9)
|
|
assert (m8.pattern.patterns[0].end_lineno, m8.pattern.patterns[0].end_col_offset) == (12, 12)
|
|
|
|
m9 = ast_nodes[7]
|
|
assert isinstance(m9, nodes.MatchCase)
|
|
assert isinstance(m9.pattern, nodes.MatchAs)
|
|
assert isinstance(m9.pattern.pattern, nodes.MatchValue)
|
|
assert isinstance(m9.pattern.name, nodes.AssignName)
|
|
assert (m9.pattern.lineno, m9.pattern.col_offset) == (14, 9)
|
|
assert (m9.pattern.end_lineno, m9.pattern.end_col_offset) == (14, 17)
|
|
assert (m9.pattern.pattern.lineno, m9.pattern.pattern.col_offset) == (14, 9)
|
|
assert (m9.pattern.pattern.end_lineno, m9.pattern.pattern.end_col_offset) == (14, 12)
|
|
# TODO fix column offset: MatchAs -> name (AssignName)
|
|
assert (m9.pattern.name.lineno, m9.pattern.name.col_offset) == (14, 9)
|
|
assert (m9.pattern.name.end_lineno, m9.pattern.name.end_col_offset) == (14, 17)
|
|
# fmt: on
|
|
|
|
@staticmethod
|
|
def test_end_lineno_comprehension() -> None:
|
|
"""ListComp, SetComp, DictComp, GeneratorExpr."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
[x for x in var] #@
|
|
{x for x in var} #@
|
|
{x: y for x, y in var} #@
|
|
(x for x in var) #@
|
|
"""
|
|
).strip()
|
|
ast_nodes = builder.extract_node(code)
|
|
assert isinstance(ast_nodes, list) and len(ast_nodes) == 4
|
|
|
|
c1 = ast_nodes[0]
|
|
assert isinstance(c1, nodes.ListComp)
|
|
assert isinstance(c1.elt, nodes.Name)
|
|
assert isinstance(c1.generators[0], nodes.Comprehension) # type: ignore
|
|
assert (c1.lineno, c1.col_offset) == (1, 0)
|
|
assert (c1.end_lineno, c1.end_col_offset) == (1, 16)
|
|
assert (c1.elt.lineno, c1.elt.col_offset) == (1, 1)
|
|
assert (c1.elt.end_lineno, c1.elt.end_col_offset) == (1, 2)
|
|
|
|
c2 = ast_nodes[1]
|
|
assert isinstance(c2, nodes.SetComp)
|
|
assert isinstance(c2.elt, nodes.Name)
|
|
assert isinstance(c2.generators[0], nodes.Comprehension) # type: ignore
|
|
assert (c2.lineno, c2.col_offset) == (2, 0)
|
|
assert (c2.end_lineno, c2.end_col_offset) == (2, 16)
|
|
assert (c2.elt.lineno, c2.elt.col_offset) == (2, 1)
|
|
assert (c2.elt.end_lineno, c2.elt.end_col_offset) == (2, 2)
|
|
|
|
c3 = ast_nodes[2]
|
|
assert isinstance(c3, nodes.DictComp)
|
|
assert isinstance(c3.key, nodes.Name)
|
|
assert isinstance(c3.value, nodes.Name)
|
|
assert isinstance(c3.generators[0], nodes.Comprehension) # type: ignore
|
|
assert (c3.lineno, c3.col_offset) == (3, 0)
|
|
assert (c3.end_lineno, c3.end_col_offset) == (3, 22)
|
|
assert (c3.key.lineno, c3.key.col_offset) == (3, 1)
|
|
assert (c3.key.end_lineno, c3.key.end_col_offset) == (3, 2)
|
|
assert (c3.value.lineno, c3.value.col_offset) == (3, 4)
|
|
assert (c3.value.end_lineno, c3.value.end_col_offset) == (3, 5)
|
|
|
|
c4 = ast_nodes[3]
|
|
assert isinstance(c4, nodes.GeneratorExp)
|
|
assert isinstance(c4.elt, nodes.Name)
|
|
assert isinstance(c4.generators[0], nodes.Comprehension) # type: ignore
|
|
assert (c4.lineno, c4.col_offset) == (4, 0)
|
|
assert (c4.end_lineno, c4.end_col_offset) == (4, 16)
|
|
assert (c4.elt.lineno, c4.elt.col_offset) == (4, 1)
|
|
assert (c4.elt.end_lineno, c4.elt.end_col_offset) == (4, 2)
|
|
|
|
@staticmethod
|
|
def test_end_lineno_class() -> None:
|
|
"""ClassDef, Keyword."""
|
|
code = textwrap.dedent(
|
|
"""
|
|
@decorator1
|
|
@decorator2
|
|
class X(Parent, var=42):
|
|
pass
|
|
"""
|
|
).strip()
|
|
c1 = builder.extract_node(code)
|
|
assert isinstance(c1, nodes.ClassDef)
|
|
assert isinstance(c1.decorators, nodes.Decorators)
|
|
assert isinstance(c1.bases[0], nodes.Name)
|
|
assert isinstance(c1.keywords[0], nodes.Keyword)
|
|
assert isinstance(c1.body[0], nodes.Pass)
|
|
|
|
# fmt: off
|
|
assert (c1.lineno, c1.col_offset) == (3, 0)
|
|
assert (c1.end_lineno, c1.end_col_offset) == (4, 8)
|
|
assert (c1.decorators.lineno, c1.decorators.col_offset) == (1, 0)
|
|
assert (c1.decorators.end_lineno, c1.decorators.end_col_offset) == (2, 11)
|
|
assert (c1.bases[0].lineno, c1.bases[0].col_offset) == (3, 8)
|
|
assert (c1.bases[0].end_lineno, c1.bases[0].end_col_offset) == (3, 14)
|
|
if PY39_PLUS:
|
|
# 'lineno' and 'col_offset' information only added in Python 3.9
|
|
assert (c1.keywords[0].lineno, c1.keywords[0].col_offset) == (3, 16)
|
|
assert (c1.keywords[0].end_lineno, c1.keywords[0].end_col_offset) == (3, 22)
|
|
else:
|
|
assert (c1.keywords[0].lineno, c1.keywords[0].col_offset) == (None, None)
|
|
assert (c1.keywords[0].end_lineno, c1.keywords[0].end_col_offset) == (None, None)
|
|
assert (c1.body[0].lineno, c1.body[0].col_offset) == (4, 4)
|
|
assert (c1.body[0].end_lineno, c1.body[0].end_col_offset) == (4, 8)
|
|
# fmt: on
|
|
|
|
@staticmethod
|
|
def test_end_lineno_module() -> None:
|
|
"""Tests for Module"""
|
|
code = """print()"""
|
|
module = astroid.parse(code)
|
|
assert isinstance(module, nodes.Module)
|
|
assert module.lineno == 0
|
|
assert module.col_offset is None
|
|
assert module.end_lineno is None
|
|
assert module.end_col_offset is None
|