From 2756944dc1c141f3e4cc35d5e1dab6b3b28c9563 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Sun, 21 Aug 2022 18:15:49 +0300 Subject: [PATCH] Make sure `ParamSpec` suffix and arg kind do match (#13468) --- mypy/typeanal.py | 8 ++++++-- test-data/unit/check-parameter-specification.test | 15 +++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/mypy/typeanal.py b/mypy/typeanal.py index ae1920e234bb..cae05f117abd 100644 --- a/mypy/typeanal.py +++ b/mypy/typeanal.py @@ -838,17 +838,21 @@ def anal_type_guard_arg(self, t: UnboundType, fullname: str) -> Type | None: def anal_star_arg_type(self, t: Type, kind: ArgKind, nested: bool) -> Type: """Analyze signature argument type for *args and **kwargs argument.""" - # TODO: Check that suffix and kind match if isinstance(t, UnboundType) and t.name and "." in t.name and not t.args: components = t.name.split(".") - sym = self.lookup_qualified(".".join(components[:-1]), t) + tvar_name = ".".join(components[:-1]) + sym = self.lookup_qualified(tvar_name, t) if sym is not None and isinstance(sym.node, ParamSpecExpr): tvar_def = self.tvar_scope.get_binding(sym) if isinstance(tvar_def, ParamSpecType): if kind == ARG_STAR: make_paramspec = paramspec_args + if components[-1] != "args": + self.fail(f'Use "{tvar_name}.args" for variadic "*" parameter', t) elif kind == ARG_STAR2: make_paramspec = paramspec_kwargs + if components[-1] != "kwargs": + self.fail(f'Use "{tvar_name}.kwargs" for variadic "**" parameter', t) else: assert False, kind return make_paramspec( diff --git a/test-data/unit/check-parameter-specification.test b/test-data/unit/check-parameter-specification.test index c3a4216a1eaf..bac23f31c289 100644 --- a/test-data/unit/check-parameter-specification.test +++ b/test-data/unit/check-parameter-specification.test @@ -1112,3 +1112,18 @@ def func(callback: Callable[P, str]) -> Callable[P, str]: return "foo" return inner [builtins fixtures/paramspec.pyi] + +[case testParamSpecArgsAndKwargsMissmatch] +from typing import Callable +from typing_extensions import ParamSpec + +P1 = ParamSpec("P1") + +def func(callback: Callable[P1, str]) -> Callable[P1, str]: + def inner( + *args: P1.kwargs, # E: Use "P1.args" for variadic "*" parameter + **kwargs: P1.args, # E: Use "P1.kwargs" for variadic "**" parameter + ) -> str: + return "foo" + return inner +[builtins fixtures/paramspec.pyi]