diff options
Diffstat (limited to 'Lib/test/test_typing.py')
-rw-r--r-- | Lib/test/test_typing.py | 180 |
1 files changed, 146 insertions, 34 deletions
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 2ab8be49b2..c340c8a898 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -25,6 +25,7 @@ from typing import IO, TextIO, BinaryIO from typing import Pattern, Match from typing import Annotated, ForwardRef from typing import TypeAlias +from typing import ParamSpec, Concatenate import abc import typing import weakref @@ -447,14 +448,6 @@ class CallableTests(BaseTestCase): def test_callable_wrong_forms(self): with self.assertRaises(TypeError): - Callable[[...], int] - with self.assertRaises(TypeError): - Callable[(), int] - with self.assertRaises(TypeError): - Callable[[()], int] - with self.assertRaises(TypeError): - Callable[[int, 1], 2] - with self.assertRaises(TypeError): Callable[int] def test_callable_instance_works(self): @@ -528,6 +521,7 @@ class LiteralTests(BaseTestCase): self.assertEqual(repr(Literal[int]), "typing.Literal[int]") self.assertEqual(repr(Literal), "typing.Literal") self.assertEqual(repr(Literal[None]), "typing.Literal[None]") + self.assertEqual(repr(Literal[1, 2, 3, 3]), "typing.Literal[1, 2, 3]") def test_cannot_init(self): with self.assertRaises(TypeError): @@ -559,6 +553,35 @@ class LiteralTests(BaseTestCase): with self.assertRaises(TypeError): Literal[1][1] + def test_equal(self): + self.assertNotEqual(Literal[0], Literal[False]) + self.assertNotEqual(Literal[True], Literal[1]) + self.assertNotEqual(Literal[1], Literal[2]) + self.assertNotEqual(Literal[1, True], Literal[1]) + self.assertEqual(Literal[1], Literal[1]) + self.assertEqual(Literal[1, 2], Literal[2, 1]) + self.assertEqual(Literal[1, 2, 3], Literal[1, 2, 3, 3]) + + def test_hash(self): + self.assertEqual(hash(Literal[1]), hash(Literal[1])) + self.assertEqual(hash(Literal[1, 2]), hash(Literal[2, 1])) + self.assertEqual(hash(Literal[1, 2, 3]), hash(Literal[1, 2, 3, 3])) + + def test_args(self): + self.assertEqual(Literal[1, 2, 3].__args__, (1, 2, 3)) + self.assertEqual(Literal[1, 2, 3, 3].__args__, (1, 2, 3)) + self.assertEqual(Literal[1, Literal[2], Literal[3, 4]].__args__, (1, 2, 3, 4)) + # Mutable arguments will not be deduplicated + self.assertEqual(Literal[[], []].__args__, ([], [])) + + def test_flatten(self): + l1 = Literal[Literal[1], Literal[2], Literal[3]] + l2 = Literal[Literal[1, 2], 3] + l3 = Literal[Literal[1, 2, 3]] + for l in l1, l2, l3: + self.assertEqual(l, Literal[1, 2, 3]) + self.assertEqual(l.__args__, (1, 2, 3)) + XK = TypeVar('XK', str, bytes) XV = TypeVar('XV') @@ -1108,10 +1131,6 @@ class ProtocolTests(BaseTestCase): PR[int] with self.assertRaises(TypeError): P[int, str] - with self.assertRaises(TypeError): - PR[int, 1] - with self.assertRaises(TypeError): - PR[int, ClassVar] class C(PR[int, T]): pass @@ -1133,8 +1152,6 @@ class ProtocolTests(BaseTestCase): self.assertIsSubclass(P, PR) with self.assertRaises(TypeError): PR[int] - with self.assertRaises(TypeError): - PR[int, 1] class P1(Protocol, Generic[T]): def bar(self, x: T) -> str: ... @@ -1153,8 +1170,6 @@ class ProtocolTests(BaseTestCase): return x self.assertIsInstance(Test(), PSub) - with self.assertRaises(TypeError): - PR[int, ClassVar] def test_init_called(self): T = TypeVar('T') @@ -1724,8 +1739,6 @@ class GenericTests(BaseTestCase): self.assertEqual(typing.Iterable[Tuple[T, T]][T], typing.Iterable[Tuple[T, T]]) with self.assertRaises(TypeError): Tuple[T, int][()] - with self.assertRaises(TypeError): - Tuple[T, U][T, ...] self.assertEqual(Union[T, int][int], int) self.assertEqual(Union[T, U][int, Union[int, str]], Union[int, str]) @@ -1737,10 +1750,6 @@ class GenericTests(BaseTestCase): self.assertEqual(Callable[[T], T][KT], Callable[[KT], KT]) self.assertEqual(Callable[..., List[T]][int], Callable[..., List[int]]) - with self.assertRaises(TypeError): - Callable[[T], U][..., int] - with self.assertRaises(TypeError): - Callable[[T], U][[], int] def test_extended_generic_rules_repr(self): T = TypeVar('T') @@ -1777,10 +1786,9 @@ class GenericTests(BaseTestCase): def test_extended_generic_rules_subclassing(self): class T1(Tuple[T, KT]): ... class T2(Tuple[T, ...]): ... - class C1(Callable[[T], T]): ... - class C2(Callable[..., int]): - def __call__(self): - return None + class C1(typing.Container[T]): + def __contains__(self, item): + return False self.assertEqual(T1.__parameters__, (T, KT)) self.assertEqual(T1[int, str].__args__, (int, str)) @@ -1794,10 +1802,9 @@ class GenericTests(BaseTestCase): ## T2[int, str] self.assertEqual(repr(C1[int]).split('.')[-1], 'C1[int]') - self.assertEqual(C2.__parameters__, ()) - self.assertIsInstance(C2(), collections.abc.Callable) - self.assertIsSubclass(C2, collections.abc.Callable) - self.assertIsSubclass(C1, collections.abc.Callable) + self.assertEqual(C1.__parameters__, (T,)) + self.assertIsInstance(C1(), collections.abc.Container) + self.assertIsSubclass(C1, collections.abc.Container) self.assertIsInstance(T1(), tuple) self.assertIsSubclass(T2, tuple) with self.assertRaises(TypeError): @@ -1831,10 +1838,6 @@ class GenericTests(BaseTestCase): class MyTup(Tuple[T, T]): ... self.assertIs(MyTup[int]().__class__, MyTup) self.assertEqual(MyTup[int]().__orig_class__, MyTup[int]) - class MyCall(Callable[..., T]): - def __call__(self): return None - self.assertIs(MyCall[T]().__class__, MyCall) - self.assertEqual(MyCall[T]().__orig_class__, MyCall[T]) class MyDict(typing.Dict[T, T]): ... self.assertIs(MyDict[int]().__class__, MyDict) self.assertEqual(MyDict[int]().__orig_class__, MyDict[int]) @@ -3865,10 +3868,14 @@ class TypedDictTests(BaseTestCase): self.assertEqual(D(), {}) self.assertEqual(D(x=1), {'x': 1}) self.assertEqual(D.__total__, False) + self.assertEqual(D.__required_keys__, frozenset()) + self.assertEqual(D.__optional_keys__, {'x'}) self.assertEqual(Options(), {}) self.assertEqual(Options(log_level=2), {'log_level': 2}) self.assertEqual(Options.__total__, False) + self.assertEqual(Options.__required_keys__, frozenset()) + self.assertEqual(Options.__optional_keys__, {'log_level', 'log_path'}) def test_optional_keys(self): class Point2Dor3D(Point2D, total=False): @@ -4223,6 +4230,111 @@ class TypeAliasTests(BaseTestCase): TypeAlias[int] +class ParamSpecTests(BaseTestCase): + + def test_basic_plain(self): + P = ParamSpec('P') + self.assertEqual(P, P) + self.assertIsInstance(P, ParamSpec) + + def test_valid_uses(self): + P = ParamSpec('P') + T = TypeVar('T') + C1 = Callable[P, int] + self.assertEqual(C1.__args__, (P, int)) + self.assertEqual(C1.__parameters__, (P,)) + C2 = Callable[P, T] + self.assertEqual(C2.__args__, (P, T)) + self.assertEqual(C2.__parameters__, (P, T)) + # Test collections.abc.Callable too. + C3 = collections.abc.Callable[P, int] + self.assertEqual(C3.__args__, (P, int)) + self.assertEqual(C3.__parameters__, (P,)) + C4 = collections.abc.Callable[P, T] + self.assertEqual(C4.__args__, (P, T)) + self.assertEqual(C4.__parameters__, (P, T)) + + # ParamSpec instances should also have args and kwargs attributes. + self.assertIn('args', dir(P)) + self.assertIn('kwargs', dir(P)) + P.args + P.kwargs + + def test_user_generics(self): + T = TypeVar("T") + P = ParamSpec("P") + P_2 = ParamSpec("P_2") + + class X(Generic[T, P]): + f: Callable[P, int] + x: T + G1 = X[int, P_2] + self.assertEqual(G1.__args__, (int, P_2)) + self.assertEqual(G1.__parameters__, (P_2,)) + + G2 = X[int, Concatenate[int, P_2]] + self.assertEqual(G2.__args__, (int, Concatenate[int, P_2])) + self.assertEqual(G2.__parameters__, (P_2,)) + + G3 = X[int, [int, bool]] + self.assertEqual(G3.__args__, (int, (int, bool))) + self.assertEqual(G3.__parameters__, ()) + + G4 = X[int, ...] + self.assertEqual(G4.__args__, (int, Ellipsis)) + self.assertEqual(G4.__parameters__, ()) + + class Z(Generic[P]): + f: Callable[P, int] + + G5 = Z[[int, str, bool]] + self.assertEqual(G5.__args__, ((int, str, bool),)) + self.assertEqual(G5.__parameters__, ()) + + G6 = Z[int, str, bool] + self.assertEqual(G6.__args__, ((int, str, bool),)) + self.assertEqual(G6.__parameters__, ()) + + # G5 and G6 should be equivalent according to the PEP + self.assertEqual(G5.__args__, G6.__args__) + self.assertEqual(G5.__origin__, G6.__origin__) + self.assertEqual(G5.__parameters__, G6.__parameters__) + self.assertEqual(G5, G6) + + def test_var_substitution(self): + T = TypeVar("T") + P = ParamSpec("P") + C1 = Callable[P, T] + self.assertEqual(C1[int, str], Callable[[int], str]) + self.assertEqual(C1[[int, str, dict], float], Callable[[int, str, dict], float]) + + +class ConcatenateTests(BaseTestCase): + def test_basics(self): + P = ParamSpec('P') + class MyClass: ... + c = Concatenate[MyClass, P] + self.assertNotEqual(c, Concatenate) + + def test_valid_uses(self): + P = ParamSpec('P') + T = TypeVar('T') + C1 = Callable[Concatenate[int, P], int] + self.assertEqual(C1.__args__, (Concatenate[int, P], int)) + self.assertEqual(C1.__parameters__, (P,)) + C2 = Callable[Concatenate[int, T, P], T] + self.assertEqual(C2.__args__, (Concatenate[int, T, P], T)) + self.assertEqual(C2.__parameters__, (T, P)) + + # Test collections.abc.Callable too. + C3 = collections.abc.Callable[Concatenate[int, P], int] + self.assertEqual(C3.__args__, (Concatenate[int, P], int)) + self.assertEqual(C3.__parameters__, (P,)) + C4 = collections.abc.Callable[Concatenate[int, T, P], T] + self.assertEqual(C4.__args__, (Concatenate[int, T, P], T)) + self.assertEqual(C4.__parameters__, (T, P)) + + class AllTests(BaseTestCase): """Tests for __all__.""" |