Skip to content

Commit 78540ab

Browse files
authored
Merge pull request #854 from python-rope/lieryan-patchedast-type-alias-type-var
Implement patchedast for TypeAlias and TypeVar/TypeVar/ParamSpec syntax
2 parents 0c77b6e + 8516dd6 commit 78540ab

3 files changed

Lines changed: 272 additions & 1 deletion

File tree

‎CHANGELOG.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# **Upcoming release**
22

33
- #850 Update and pin black version in pre-commit and Github Actions
4-
- #850 Bump supported python version to up to Python 3.14
4+
- #851 Bump supported python version to up to Python 3.14
5+
- #852 Implement patchedast handlers for TypeAlias
6+
- #853 Implement patchedast handlers TypeVar
57

68
# Release 1.14.0
79

‎rope/refactor/patchedast.py‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,9 @@ def _handle_function_def_node(self, node, is_async):
491491
children.extend(("@", decorator))
492492
children.extend(["async", "def"] if is_async else ["def"])
493493
children.append(node.name)
494+
type_params = getattr(node, "type_params", [])
495+
if type_params:
496+
children.extend(["[", *self._child_nodes(type_params, ","), "]"])
494497
children.extend(["(", node.args, ")"])
495498
children.append(":")
496499
children.extend(node.body)
@@ -825,6 +828,32 @@ def _MatchMapping(self, node):
825828
children.append("}")
826829
self._handle(node, children)
827830

831+
def _TypeAlias(self, node):
832+
children = ["type", node.name, node.value]
833+
self._handle(node, children)
834+
835+
def _TypeVar(self, node):
836+
children = [node.name]
837+
if node.bound:
838+
children.extend([":", node.bound])
839+
self._handle_default_value(node, children)
840+
self._handle(node, children)
841+
842+
def _TypeVarTuple(self, node):
843+
children = ["*", node.name]
844+
self._handle_default_value(node, children)
845+
self._handle(node, children)
846+
847+
def _ParamSpec(self, node):
848+
children = ["**", node.name]
849+
self._handle_default_value(node, children)
850+
self._handle(node, children)
851+
852+
def _handle_default_value(self, node, children):
853+
default_value = getattr(node, "default_value", None)
854+
if default_value:
855+
children.extend(["=", default_value])
856+
828857

829858
class _Source:
830859
def __init__(self, source):

‎ropetest/refactor/patchedasttest.py‎

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,60 @@ def assert_single_case_match_block(self, checker, match_type):
3737
"Expr",
3838
])
3939

40+
def assert_function_def_has_one_type_var(self, checker):
41+
checker.check_children(
42+
"FunctionDef",
43+
[
44+
"def",
45+
" ",
46+
"foo",
47+
"",
48+
"[", "", "TypeVar", "", "]",
49+
"",
50+
"(", "", "arguments", "", ")",
51+
"",
52+
":",
53+
"\n ",
54+
"Pass",
55+
],
56+
)
57+
58+
def assert_function_def_has_one_type_var_tuple(self, checker):
59+
checker.check_children(
60+
"FunctionDef",
61+
[
62+
"def",
63+
" ",
64+
"foo",
65+
"",
66+
"[", "", "TypeVarTuple", "", "]",
67+
"",
68+
"(", "", "arguments", "", ")",
69+
"",
70+
":",
71+
"\n ",
72+
"Pass",
73+
],
74+
)
75+
76+
def assert_function_def_has_one_param_spec(self, checker):
77+
checker.check_children(
78+
"FunctionDef",
79+
[
80+
"def",
81+
" ",
82+
"foo",
83+
"",
84+
"[", "", "ParamSpec", "", "]",
85+
"",
86+
"(", "", "arguments", "", ")",
87+
"",
88+
":",
89+
"\n ",
90+
"Pass",
91+
],
92+
)
93+
4094
def test_operator_support_completeness(self):
4195
ast_ops = {
4296
n.__name__
@@ -1510,6 +1564,192 @@ def test_match_node_with_match_mapping_match_as(self):
15101564
"}",
15111565
])
15121566

1567+
@testutils.only_for_versions_higher("3.12")
1568+
def test_type_alias(self):
1569+
source = dedent("""\
1570+
type Point = tuple[float, float]
1571+
""")
1572+
ast_frag = patchedast.get_patched_ast(source, True)
1573+
checker = _ResultChecker(self, ast_frag)
1574+
checker.check_children("TypeAlias", [
1575+
"type",
1576+
" ",
1577+
"Name",
1578+
" = ",
1579+
"Subscript",
1580+
])
1581+
1582+
@testutils.only_for_versions_higher("3.12")
1583+
def test_type_var_simple(self):
1584+
source = dedent("""\
1585+
def foo[S, T](x):
1586+
pass
1587+
""")
1588+
ast_frag = patchedast.get_patched_ast(source, True)
1589+
checker = _ResultChecker(self, ast_frag)
1590+
1591+
checker.check_children(
1592+
"FunctionDef",
1593+
[
1594+
"def",
1595+
" ",
1596+
"foo",
1597+
"",
1598+
"[",
1599+
"",
1600+
"TypeVar",
1601+
"",
1602+
",",
1603+
" ",
1604+
"TypeVar",
1605+
"",
1606+
"]",
1607+
"",
1608+
"(", "", "arguments", "", ")",
1609+
"",
1610+
":",
1611+
"\n ",
1612+
"Pass",
1613+
],
1614+
)
1615+
1616+
@testutils.only_for_versions_higher("3.13")
1617+
def test_type_var_with_default_value(self):
1618+
source = dedent("""\
1619+
def foo[T = D](x):
1620+
pass
1621+
""")
1622+
ast_frag = patchedast.get_patched_ast(source, True)
1623+
checker = _ResultChecker(self, ast_frag)
1624+
1625+
self.assert_function_def_has_one_type_var(checker)
1626+
1627+
checker.check_children("TypeVar", [
1628+
"T",
1629+
" ",
1630+
"=",
1631+
" ",
1632+
"Name",
1633+
])
1634+
1635+
@testutils.only_for_versions_higher("3.12")
1636+
def test_type_var_with_constraint(self):
1637+
source = dedent("""\
1638+
def foo[T: (A, B)](x):
1639+
pass
1640+
""")
1641+
ast_frag = patchedast.get_patched_ast(source, True)
1642+
checker = _ResultChecker(self, ast_frag)
1643+
1644+
self.assert_function_def_has_one_type_var(checker)
1645+
1646+
checker.check_children("TypeVar", [
1647+
"T",
1648+
"",
1649+
":",
1650+
" ",
1651+
"Tuple",
1652+
])
1653+
1654+
@testutils.only_for_versions_higher("3.13")
1655+
def test_type_var_with_constraint_and_default_value(self):
1656+
source = dedent("""\
1657+
def foo[T: (A, B) = D](x):
1658+
pass
1659+
""")
1660+
ast_frag = patchedast.get_patched_ast(source, True)
1661+
checker = _ResultChecker(self, ast_frag)
1662+
1663+
self.assert_function_def_has_one_type_var(checker)
1664+
1665+
checker.check_children("TypeVar", [
1666+
"T",
1667+
"",
1668+
":",
1669+
" ",
1670+
"Tuple",
1671+
" ",
1672+
"=",
1673+
" ",
1674+
"Name",
1675+
])
1676+
1677+
@testutils.only_for_versions_higher("3.12")
1678+
def test_type_var_tuple_simple(self):
1679+
source = dedent("""\
1680+
def foo[*T](x):
1681+
pass
1682+
""")
1683+
ast_frag = patchedast.get_patched_ast(source, True)
1684+
checker = _ResultChecker(self, ast_frag)
1685+
1686+
self.assert_function_def_has_one_type_var_tuple(checker)
1687+
1688+
checker.check_children("TypeVarTuple", [
1689+
"*",
1690+
"",
1691+
"T",
1692+
])
1693+
1694+
@testutils.only_for_versions_higher("3.13")
1695+
def test_type_var_tuple_with_default_value(self):
1696+
source = dedent("""\
1697+
def foo[*T = (A, B)](x):
1698+
pass
1699+
""")
1700+
ast_frag = patchedast.get_patched_ast(source, True)
1701+
checker = _ResultChecker(self, ast_frag)
1702+
1703+
self.assert_function_def_has_one_type_var_tuple(checker)
1704+
1705+
checker.check_children("TypeVarTuple", [
1706+
"*",
1707+
"",
1708+
"T",
1709+
" ",
1710+
"=",
1711+
" ",
1712+
"Tuple",
1713+
])
1714+
1715+
@testutils.only_for_versions_higher("3.12")
1716+
def test_param_spec_simple(self):
1717+
source = dedent("""\
1718+
def foo[**T](x):
1719+
pass
1720+
""")
1721+
ast_frag = patchedast.get_patched_ast(source, True)
1722+
checker = _ResultChecker(self, ast_frag)
1723+
1724+
self.assert_function_def_has_one_param_spec(checker)
1725+
1726+
checker.check_children("ParamSpec", [
1727+
"**",
1728+
"",
1729+
"T",
1730+
])
1731+
1732+
@testutils.only_for_versions_higher("3.13")
1733+
def test_param_spec_with_default_value(self):
1734+
source = dedent("""\
1735+
def foo[**T = (A, B)](x):
1736+
pass
1737+
""")
1738+
ast_frag = patchedast.get_patched_ast(source, True)
1739+
checker = _ResultChecker(self, ast_frag)
1740+
1741+
self.assert_function_def_has_one_param_spec(checker)
1742+
1743+
checker.check_children("ParamSpec", [
1744+
"**",
1745+
"",
1746+
"T",
1747+
" ",
1748+
"=",
1749+
" ",
1750+
"Tuple",
1751+
])
1752+
15131753

15141754
class _ResultChecker:
15151755
def __init__(self, test_case, ast):

0 commit comments

Comments
 (0)