summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_typing.py
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2022-03-11 08:47:26 (GMT)
committerGitHub <noreply@github.com>2022-03-11 08:47:26 (GMT)
commitb6a5d8590c4bfe4553d796b36af03bda8c0d5af5 (patch)
tree7cf1db87de08ddb22cc31ca426427e9f559dc321 /Lib/test/test_typing.py
parent2d5835a019a46573d5b1b614c8ef88d6b564d8d4 (diff)
downloadcpython-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.py60
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