Skip to content

Commit a579db6

Browse files
authored
Merge pull request #868 from asottile/pep464-when-mypy-does-it
rewrite pep 646 Unpack to splat in `*args`
2 parents 4771f05 + 2a996f9 commit a579db6

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

pyupgrade/_plugins/typing_pep646_unpack.py

+39
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,42 @@ def visit_Subscript(
3737
if is_name_attr(node.value, state.from_imports, ('typing',), ('Unpack',)):
3838
if isinstance(parent, (ast.Subscript, ast.Index)):
3939
yield ast_to_offset(node.value), _replace_unpack_with_star
40+
41+
42+
def _visit_func(
43+
state: State,
44+
node: ast.AsyncFunctionDef | ast.FunctionDef,
45+
parent: ast.AST,
46+
) -> Iterable[tuple[Offset, TokenFunc]]:
47+
if state.settings.min_version < (3, 11):
48+
return
49+
50+
vararg = node.args.vararg
51+
if (
52+
vararg is not None and
53+
isinstance(vararg.annotation, ast.Subscript) and
54+
is_name_attr(
55+
vararg.annotation.value,
56+
state.from_imports,
57+
('typing',), ('Unpack',),
58+
)
59+
):
60+
yield ast_to_offset(vararg.annotation.value), _replace_unpack_with_star
61+
62+
63+
@register(ast.AsyncFunctionDef)
64+
def visit_AsyncFunctionDef(
65+
state: State,
66+
node: ast.AsyncFunctionDef,
67+
parent: ast.AST,
68+
) -> Iterable[tuple[Offset, TokenFunc]]:
69+
yield from _visit_func(state, node, parent)
70+
71+
72+
@register(ast.FunctionDef)
73+
def visit_FunctionDef(
74+
state: State,
75+
node: ast.FunctionDef,
76+
parent: ast.AST,
77+
) -> Iterable[tuple[Offset, TokenFunc]]:
78+
yield from _visit_func(state, node, parent)

tests/features/typing_pep646_unpack_test.py

+17
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@
2121
' pass',
2222
id='Not inside a subscript',
2323
),
24+
pytest.param(
25+
'from typing import Unpack\n'
26+
'from typing import TypedDict\n'
27+
'class D(TypedDict):\n'
28+
' x: int\n'
29+
'def f(**kwargs: Unpack[D]) -> None: pass\n',
30+
id='3.12 TypedDict for kwargs',
31+
),
2432
),
2533
)
2634
def test_fix_pep646_noop(s):
@@ -53,6 +61,15 @@ def test_fix_pep646_noop(s):
5361
'class C(Generic[*Shape]):\n'
5462
' pass',
5563
),
64+
pytest.param(
65+
'from typing import Unpack\n'
66+
'def f(*args: Unpack[tuple[int, ...]]): pass\n',
67+
68+
'from typing import Unpack\n'
69+
'def f(*args: *tuple[int, ...]): pass\n',
70+
71+
id='Unpack for *args',
72+
),
5673
),
5774
)
5875
def test_typing_unpack(s, expected):

0 commit comments

Comments
 (0)