summaryrefslogtreecommitdiffstats
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.py190
1 files changed, 189 insertions, 1 deletions
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 703fe84..112db03 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -38,7 +38,7 @@ from typing import Annotated, ForwardRef
from typing import Self, LiteralString
from typing import TypeAlias
from typing import ParamSpec, Concatenate, ParamSpecArgs, ParamSpecKwargs
-from typing import TypeGuard, TypeIs
+from typing import TypeGuard, TypeIs, NoDefault
import abc
import textwrap
import typing
@@ -580,6 +580,174 @@ class TypeVarTests(BaseTestCase):
self.assertIs(T.__bound__, None)
+class TypeParameterDefaultsTests(BaseTestCase):
+ def test_typevar(self):
+ T = TypeVar('T', default=int)
+ self.assertEqual(T.__default__, int)
+ self.assertTrue(T.has_default())
+ self.assertIsInstance(T, TypeVar)
+
+ class A(Generic[T]): ...
+ Alias = Optional[T]
+
+ def test_typevar_none(self):
+ U = TypeVar('U')
+ U_None = TypeVar('U_None', default=None)
+ self.assertIs(U.__default__, NoDefault)
+ self.assertFalse(U.has_default())
+ self.assertIs(U_None.__default__, None)
+ self.assertTrue(U_None.has_default())
+
+ class X[T]: ...
+ T, = X.__type_params__
+ self.assertIs(T.__default__, NoDefault)
+ self.assertFalse(T.has_default())
+
+ def test_paramspec(self):
+ P = ParamSpec('P', default=(str, int))
+ self.assertEqual(P.__default__, (str, int))
+ self.assertTrue(P.has_default())
+ self.assertIsInstance(P, ParamSpec)
+
+ class A(Generic[P]): ...
+ Alias = typing.Callable[P, None]
+
+ P_default = ParamSpec('P_default', default=...)
+ self.assertIs(P_default.__default__, ...)
+
+ def test_paramspec_none(self):
+ U = ParamSpec('U')
+ U_None = ParamSpec('U_None', default=None)
+ self.assertIs(U.__default__, NoDefault)
+ self.assertFalse(U.has_default())
+ self.assertIs(U_None.__default__, None)
+ self.assertTrue(U_None.has_default())
+
+ class X[**P]: ...
+ P, = X.__type_params__
+ self.assertIs(P.__default__, NoDefault)
+ self.assertFalse(P.has_default())
+
+ def test_typevartuple(self):
+ Ts = TypeVarTuple('Ts', default=Unpack[Tuple[str, int]])
+ self.assertEqual(Ts.__default__, Unpack[Tuple[str, int]])
+ self.assertTrue(Ts.has_default())
+ self.assertIsInstance(Ts, TypeVarTuple)
+
+ class A(Generic[Unpack[Ts]]): ...
+ Alias = Optional[Unpack[Ts]]
+
+ def test_typevartuple_specialization(self):
+ T = TypeVar("T")
+ Ts = TypeVarTuple('Ts', default=Unpack[Tuple[str, int]])
+ self.assertEqual(Ts.__default__, Unpack[Tuple[str, int]])
+ class A(Generic[T, Unpack[Ts]]): ...
+ self.assertEqual(A[float].__args__, (float, str, int))
+ self.assertEqual(A[float, range].__args__, (float, range))
+ self.assertEqual(A[float, *tuple[int, ...]].__args__, (float, *tuple[int, ...]))
+
+ def test_typevar_and_typevartuple_specialization(self):
+ T = TypeVar("T")
+ U = TypeVar("U", default=float)
+ Ts = TypeVarTuple('Ts', default=Unpack[Tuple[str, int]])
+ self.assertEqual(Ts.__default__, Unpack[Tuple[str, int]])
+ class A(Generic[T, U, Unpack[Ts]]): ...
+ self.assertEqual(A[int].__args__, (int, float, str, int))
+ self.assertEqual(A[int, str].__args__, (int, str, str, int))
+ self.assertEqual(A[int, str, range].__args__, (int, str, range))
+ self.assertEqual(A[int, str, *tuple[int, ...]].__args__, (int, str, *tuple[int, ...]))
+
+ def test_no_default_after_typevar_tuple(self):
+ T = TypeVar("T", default=int)
+ Ts = TypeVarTuple("Ts")
+ Ts_default = TypeVarTuple("Ts_default", default=Unpack[Tuple[str, int]])
+
+ with self.assertRaises(TypeError):
+ class X(Generic[*Ts, T]): ...
+
+ with self.assertRaises(TypeError):
+ class Y(Generic[*Ts_default, T]): ...
+
+ def test_paramspec_specialization(self):
+ T = TypeVar("T")
+ P = ParamSpec('P', default=[str, int])
+ self.assertEqual(P.__default__, [str, int])
+ class A(Generic[T, P]): ...
+ self.assertEqual(A[float].__args__, (float, (str, int)))
+ self.assertEqual(A[float, [range]].__args__, (float, (range,)))
+
+ def test_typevar_and_paramspec_specialization(self):
+ T = TypeVar("T")
+ U = TypeVar("U", default=float)
+ P = ParamSpec('P', default=[str, int])
+ self.assertEqual(P.__default__, [str, int])
+ class A(Generic[T, U, P]): ...
+ self.assertEqual(A[float].__args__, (float, float, (str, int)))
+ self.assertEqual(A[float, int].__args__, (float, int, (str, int)))
+ self.assertEqual(A[float, int, [range]].__args__, (float, int, (range,)))
+
+ def test_paramspec_and_typevar_specialization(self):
+ T = TypeVar("T")
+ P = ParamSpec('P', default=[str, int])
+ U = TypeVar("U", default=float)
+ self.assertEqual(P.__default__, [str, int])
+ class A(Generic[T, P, U]): ...
+ self.assertEqual(A[float].__args__, (float, (str, int), float))
+ self.assertEqual(A[float, [range]].__args__, (float, (range,), float))
+ self.assertEqual(A[float, [range], int].__args__, (float, (range,), int))
+
+ def test_typevartuple_none(self):
+ U = TypeVarTuple('U')
+ U_None = TypeVarTuple('U_None', default=None)
+ self.assertIs(U.__default__, NoDefault)
+ self.assertFalse(U.has_default())
+ self.assertIs(U_None.__default__, None)
+ self.assertTrue(U_None.has_default())
+
+ class X[**Ts]: ...
+ Ts, = X.__type_params__
+ self.assertIs(Ts.__default__, NoDefault)
+ self.assertFalse(Ts.has_default())
+
+ def test_no_default_after_non_default(self):
+ DefaultStrT = TypeVar('DefaultStrT', default=str)
+ T = TypeVar('T')
+
+ with self.assertRaisesRegex(
+ TypeError, r"Type parameter ~T without a default follows type parameter with a default"
+ ):
+ Test = Generic[DefaultStrT, T]
+
+ def test_need_more_params(self):
+ DefaultStrT = TypeVar('DefaultStrT', default=str)
+ T = TypeVar('T')
+ U = TypeVar('U')
+
+ class A(Generic[T, U, DefaultStrT]): ...
+ A[int, bool]
+ A[int, bool, str]
+
+ with self.assertRaisesRegex(
+ TypeError, r"Too few arguments for .+; actual 1, expected at least 2"
+ ):
+ Test = A[int]
+
+ def test_pickle(self):
+ global U, U_co, U_contra, U_default # pickle wants to reference the class by name
+ U = TypeVar('U')
+ U_co = TypeVar('U_co', covariant=True)
+ U_contra = TypeVar('U_contra', contravariant=True)
+ U_default = TypeVar('U_default', default=int)
+ for proto in range(pickle.HIGHEST_PROTOCOL):
+ for typevar in (U, U_co, U_contra, U_default):
+ z = pickle.loads(pickle.dumps(typevar, proto))
+ self.assertEqual(z.__name__, typevar.__name__)
+ self.assertEqual(z.__covariant__, typevar.__covariant__)
+ self.assertEqual(z.__contravariant__, typevar.__contravariant__)
+ self.assertEqual(z.__bound__, typevar.__bound__)
+ self.assertEqual(z.__default__, typevar.__default__)
+
+
def template_replace(templates: list[str], replacements: dict[str, list[str]]) -> list[tuple[str]]:
"""Renders templates with possible combinations of replacements.
@@ -10001,6 +10169,26 @@ class DataclassTransformTests(BaseTestCase):
self.assertIsInstance(CustomerModel, Decorated)
+class NoDefaultTests(BaseTestCase):
+ def test_pickling(self):
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ s = pickle.dumps(NoDefault, proto)
+ loaded = pickle.loads(s)
+ self.assertIs(NoDefault, loaded)
+
+ def test_constructor(self):
+ self.assertIs(NoDefault, type(NoDefault)())
+ with self.assertRaises(TypeError):
+ NoDefault(1)
+
+ def test_repr(self):
+ self.assertEqual(repr(NoDefault), 'typing.NoDefault')
+
+ def test_no_call(self):
+ with self.assertRaises(TypeError):
+ NoDefault()
+
+
class AllTests(BaseTestCase):
"""Tests for __all__."""