Skip to content

Commit 16050ab

Browse files
authored
Merge pull request #845 from marlon-costa-dc/fix/pep695-and-match-patchedast-handlers
Support PEP 695 type parameters on class definitions and type aliases
2 parents e1f2cc2 + 5055652 commit 16050ab

3 files changed

Lines changed: 89 additions & 4 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- #623, #819, #863 Support MatchOr, MatchSequence, MatchStar (@jheld, @lieryan)
99
- #870 Add default implementation for is_dir() (@lieryan)
1010
- #872 Fix unicode handling in patchedast (@lieryan)
11+
- #845 Support PEP 695 type parameters on class definitions and type aliases in patchedast (@marlon-costa-dc)
1112

1213
# Release 1.14.0
1314

‎rope/refactor/patchedast.py‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ def _ClassDef(self, node):
327327
for decorator in node.decorator_list:
328328
children.extend(("@", decorator))
329329
children.extend(["class", node.name])
330+
self._add_type_params(node, children)
330331
if node.bases:
331332
children.append("(")
332333
children.extend(self._child_nodes(node.bases, ","))
@@ -493,9 +494,7 @@ def _handle_function_def_node(self, node, is_async):
493494
children.extend(("@", decorator))
494495
children.extend(["async", "def"] if is_async else ["def"])
495496
children.append(node.name)
496-
type_params = getattr(node, "type_params", [])
497-
if type_params:
498-
children.extend(["[", *self._child_nodes(type_params, ","), "]"])
497+
self._add_type_params(node, children)
499498
children.extend(["(", node.args, ")"])
500499
children.append(":")
501500
children.extend(node.body)
@@ -872,9 +871,17 @@ def _MatchMapping(self, node):
872871
self._handle(node, children)
873872

874873
def _TypeAlias(self, node):
875-
children = ["type", node.name, node.value]
874+
children = ["type", node.name]
875+
self._add_type_params(node, children)
876+
children.append(node.value)
876877
self._handle(node, children)
877878

879+
def _add_type_params(self, node, children):
880+
"""Append the PEP 695 ``[T, ...]`` clause of a def, class or type alias."""
881+
type_params = getattr(node, "type_params", [])
882+
if type_params:
883+
children.extend(["[", *self._child_nodes(type_params, ","), "]"])
884+
878885
def _TypeVar(self, node):
879886
children = [node.name]
880887
if node.bound:

‎ropetest/refactor/patchedasttest.py‎

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,83 @@ def test_handling_format_strings_basic(self):
326326
checker.check_children("JoinedStr", ['f"', "abc", "FormattedValue", "", '"'])
327327
checker.check_children("FormattedValue", ["{", "", "Name", "", "}"])
328328

329+
@testutils.only_for_versions_higher("3.12")
330+
def test_handling_pep695_type_alias(self):
331+
source = dedent("""\
332+
type Alias[T] = list[T]
333+
""")
334+
ast_frag = patchedast.get_patched_ast(source, True)
335+
checker = _ResultChecker(self, ast_frag)
336+
checker.check_children(
337+
"TypeAlias",
338+
["type", " ", "Name", "", "[", "", "TypeVar", "", "]", " = ",
339+
"Subscript"],
340+
)
341+
342+
@testutils.only_for_versions_higher("3.12")
343+
def test_handling_pep695_generic_function(self):
344+
# TP occurs only in the type parameter list, so its region can only
345+
# come from the "[TP]" clause rendered between the name and "(".
346+
source = dedent("""\
347+
def f[TP](x):
348+
return x
349+
""")
350+
ast_frag = patchedast.get_patched_ast(source, True)
351+
checker = _ResultChecker(self, ast_frag)
352+
checker.check_children(
353+
"FunctionDef",
354+
["def", " ", "f", "", "[", "", "TypeVar", "", "]", "", "(", "",
355+
"arguments", "", ")", "", ":", "\n ", "Return"],
356+
)
357+
start = source.index("TP")
358+
checker.check_region("TypeVar", start, start + len("TP"))
359+
360+
@testutils.only_for_versions_higher("3.12")
361+
def test_handling_pep695_generic_class(self):
362+
source = dedent("""\
363+
class C[TP]:
364+
pass
365+
""")
366+
ast_frag = patchedast.get_patched_ast(source, True)
367+
checker = _ResultChecker(self, ast_frag)
368+
checker.check_children(
369+
"ClassDef",
370+
["class", " ", "C", "", "[", "", "TypeVar", "", "]", "", ":",
371+
"\n ", "Pass"],
372+
)
373+
start = source.index("TP")
374+
checker.check_region("TypeVar", start, start + len("TP"))
375+
376+
@testutils.only_for_versions_higher("3.10")
377+
def test_handling_match_sequence_and_star(self):
378+
source = dedent("""\
379+
match x:
380+
case [1, *rest]:
381+
pass
382+
""")
383+
ast_frag = patchedast.get_patched_ast(source, True)
384+
checker = _ResultChecker(self, ast_frag)
385+
checker.check_children(
386+
"MatchSequence",
387+
["[", "", "MatchValue", "", ",", " ", "MatchStar", "", "]"],
388+
)
389+
start = source.index("[1, *rest]")
390+
checker.check_region("MatchSequence", start, start + len("[1, *rest]"))
391+
checker.check_children("MatchStar", ["*", "", "rest"])
392+
393+
@testutils.only_for_versions_higher("3.10")
394+
def test_handling_match_or_and_singleton(self):
395+
source = dedent("""\
396+
match x:
397+
case 1 | None:
398+
pass
399+
""")
400+
ast_frag = patchedast.get_patched_ast(source, True)
401+
checker = _ResultChecker(self, ast_frag)
402+
checker.check_children(
403+
"MatchOr", ["MatchValue", " ", "|", " ", "MatchSingleton"]
404+
)
405+
329406
@testutils.only_for_versions_higher("3.6")
330407
def test_handling_format_strings_with_implicit_join(self):
331408
source = '''"1" + rf'abc{a}' f"""xxx{b} """\n'''

0 commit comments

Comments
 (0)