mirror of
https://github.com/python/cpython.git
synced 2025-08-30 21:48:47 +00:00
gh-116126: Implement PEP 696 (#116129)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> Co-authored-by: Shantanu <12621235+hauntsaninja@users.noreply.github.com>
This commit is contained in:
parent
852263e108
commit
ca269e58c2
28 changed files with 1924 additions and 623 deletions
|
@ -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__."""
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue