summaryrefslogtreecommitdiff
path: root/Lib/test/test_typing.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_typing.py')
-rw-r--r--Lib/test/test_typing.py180
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__."""