diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2022-03-11 08:47:26 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-11 08:47:26 (GMT) |
commit | b6a5d8590c4bfe4553d796b36af03bda8c0d5af5 (patch) | |
tree | 7cf1db87de08ddb22cc31ca426427e9f559dc321 /Lib/test/test_typing.py | |
parent | 2d5835a019a46573d5b1b614c8ef88d6b564d8d4 (diff) | |
download | cpython-b6a5d8590c4bfe4553d796b36af03bda8c0d5af5.zip cpython-b6a5d8590c4bfe4553d796b36af03bda8c0d5af5.tar.gz cpython-b6a5d8590c4bfe4553d796b36af03bda8c0d5af5.tar.bz2 |
bpo-44796: Unify TypeVar and ParamSpec substitution (GH-31143)
Add methods __typing_subst__() in TypeVar and ParamSpec.
Simplify code by using more object-oriented approach, especially
the C code for types.GenericAlias and the Python code for
collections.abc.Callable.
Diffstat (limited to 'Lib/test/test_typing.py')
-rw-r--r-- | Lib/test/test_typing.py | 60 |
1 files changed, 40 insertions, 20 deletions
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index fc596e4..91b2e77 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -360,11 +360,32 @@ class TypeVarTests(BaseTestCase): with self.assertRaises(ValueError): TypeVar('T', covariant=True, contravariant=True) + def test_var_substitution(self): + T = TypeVar('T') + subst = T.__typing_subst__ + self.assertIs(subst(int), int) + self.assertEqual(subst(list[int]), list[int]) + self.assertEqual(subst(List[int]), List[int]) + self.assertEqual(subst(List), List) + self.assertIs(subst(Any), Any) + self.assertIs(subst(None), type(None)) + self.assertIs(subst(T), T) + self.assertEqual(subst(int|str), int|str) + self.assertEqual(subst(Union[int, str]), Union[int, str]) + def test_bad_var_substitution(self): T = TypeVar('T') - for arg in (), (int, str): + P = ParamSpec("P") + bad_args = ( + 42, ..., [int], (), (int, str), Union, + Generic, Generic[T], Protocol, Protocol[T], + Final, Final[int], ClassVar, ClassVar[int], + ) + for arg in bad_args: with self.subTest(arg=arg): with self.assertRaises(TypeError): + T.__typing_subst__(arg) + with self.assertRaises(TypeError): List[T][arg] with self.assertRaises(TypeError): list[T][arg] @@ -1110,8 +1131,7 @@ class BaseCallableTests: C2 = Callable[[KT, T], VT] C3 = Callable[..., T] self.assertEqual(C1[str], Callable[[int, str], str]) - if Callable is typing.Callable: - self.assertEqual(C1[None], Callable[[int, type(None)], type(None)]) + self.assertEqual(C1[None], Callable[[int, type(None)], type(None)]) self.assertEqual(C2[int, float, str], Callable[[int, float], str]) self.assertEqual(C3[int], Callable[..., int]) self.assertEqual(C3[NoReturn], Callable[..., NoReturn]) @@ -2696,7 +2716,10 @@ class GenericTests(BaseTestCase): for obj in objs: self.assertNotEqual(repr(obj), '') self.assertEqual(obj, obj) - if getattr(obj, '__parameters__', None) and len(obj.__parameters__) == 1: + if (getattr(obj, '__parameters__', None) + and not isinstance(obj, typing.TypeVar) + and isinstance(obj.__parameters__, tuple) + and len(obj.__parameters__) == 1): self.assertEqual(obj[Any].__args__, (Any,)) if isinstance(obj, type): for base in obj.__mro__: @@ -5748,6 +5771,17 @@ class ParamSpecTests(BaseTestCase): self.assertEqual(G1.__args__, ((int, str), (bytes,))) self.assertEqual(G2.__args__, ((int,), (str, bytes))) + def test_var_substitution(self): + T = TypeVar("T") + P = ParamSpec("P") + subst = P.__typing_subst__ + self.assertEqual(subst((int, str)), (int, str)) + self.assertEqual(subst([int, str]), (int, str)) + self.assertEqual(subst([None]), (type(None),)) + self.assertIs(subst(...), ...) + self.assertIs(subst(P), P) + self.assertEqual(subst(Concatenate[int, P]), Concatenate[int, P]) + def test_bad_var_substitution(self): T = TypeVar('T') P = ParamSpec('P') @@ -5755,26 +5789,12 @@ class ParamSpecTests(BaseTestCase): for arg in bad_args: with self.subTest(arg=arg): with self.assertRaises(TypeError): + P.__typing_subst__(arg) + with self.assertRaises(TypeError): typing.Callable[P, T][arg, str] with self.assertRaises(TypeError): collections.abc.Callable[P, T][arg, str] - def test_no_paramspec_in__parameters__(self): - # ParamSpec should not be found in __parameters__ - # of generics. Usages outside Callable, Concatenate - # and Generic are invalid. - T = TypeVar("T") - P = ParamSpec("P") - self.assertNotIn(P, List[P].__parameters__) - self.assertIn(T, Tuple[T, P].__parameters__) - - # Test for consistency with builtin generics. - self.assertNotIn(P, list[P].__parameters__) - self.assertIn(T, tuple[T, P].__parameters__) - - self.assertNotIn(P, (list[P] | int).__parameters__) - self.assertIn(T, (tuple[T, P] | int).__parameters__) - def test_paramspec_in_nested_generics(self): # Although ParamSpec should not be found in __parameters__ of most # generics, they probably should be found when nested in |