diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index fbdf634c5c3be8..6cd83a1586a136 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -626,8 +626,6 @@ def test_consistency(self): self.assertEqual(c1.__args__, c2.__args__) self.assertEqual(hash(c1.__args__), hash(c2.__args__)) - test_errors = skip("known bug #44793")(BaseCallableTests.test_errors) - class CollectionsCallableTests(BaseCallableTests, BaseTestCase): Callable = collections.abc.Callable @@ -4588,6 +4586,10 @@ class X(Generic[T, P]): G1 = X[int, P_2] self.assertEqual(G1.__args__, (int, P_2)) self.assertEqual(G1.__parameters__, (P_2,)) + with self.assertRaisesRegex(TypeError, "few arguments for"): + X[int] + with self.assertRaisesRegex(TypeError, "many arguments for"): + X[int, P_2, str] G2 = X[int, Concatenate[int, P_2]] self.assertEqual(G2.__args__, (int, Concatenate[int, P_2])) diff --git a/Lib/typing.py b/Lib/typing.py index 702bb647269d0b..16ad5ce7c2d04b 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -228,7 +228,7 @@ def _check_generic(cls, parameters, elen): raise TypeError(f"{cls} is not a generic class") alen = len(parameters) if alen != elen: - raise TypeError(f"Too {'many' if alen > elen else 'few'} parameters for {cls};" + raise TypeError(f"Too {'many' if alen > elen else 'few'} arguments for {cls};" f" actual {alen}, expected {elen}") def _prepare_paramspec_params(cls, params): @@ -239,6 +239,7 @@ def _prepare_paramspec_params(cls, params): if len(cls.__parameters__) == 1 and len(params) > 1: return (params,) else: + _check_generic(cls, params, len(cls.__parameters__)) _params = [] # Convert lists to tuples to help other libraries cache the results. for p, tvar in zip(params, cls.__parameters__): @@ -1022,10 +1023,11 @@ def __getitem__(self, params): if not isinstance(params, tuple): params = (params,) params = tuple(_type_convert(p) for p in params) - if self._paramspec_tvars: - if any(isinstance(t, ParamSpec) for t in self.__parameters__): - params = _prepare_paramspec_params(self, params) - _check_generic(self, params, len(self.__parameters__)) + if (self._paramspec_tvars + and any(isinstance(t, ParamSpec) for t in self.__parameters__)): + params = _prepare_paramspec_params(self, params) + else: + _check_generic(self, params, len(self.__parameters__)) subst = dict(zip(self.__parameters__, params)) new_args = [] @@ -1292,7 +1294,8 @@ def __class_getitem__(cls, params): # Subscripting a regular Generic subclass. if any(isinstance(t, ParamSpec) for t in cls.__parameters__): params = _prepare_paramspec_params(cls, params) - _check_generic(cls, params, len(cls.__parameters__)) + else: + _check_generic(cls, params, len(cls.__parameters__)) return _GenericAlias(cls, params, _typevar_types=(TypeVar, ParamSpec), _paramspec_tvars=True) diff --git a/Misc/NEWS.d/next/Library/2021-07-31-20-28-20.bpo-44793.woaQSg.rst b/Misc/NEWS.d/next/Library/2021-07-31-20-28-20.bpo-44793.woaQSg.rst new file mode 100644 index 00000000000000..1d94d67615a479 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-07-31-20-28-20.bpo-44793.woaQSg.rst @@ -0,0 +1,2 @@ +Fix checking the number of arguments when subscribe a generic type with +``ParamSpec`` parameter.