Merge pull request #3877 from moreal/update-typing-3105

Update `typing` module to 3.10.5
This commit is contained in:
Jeong YunWon
2022-07-14 02:23:22 +09:00
committed by GitHub
4 changed files with 461 additions and 52 deletions

10
Lib/test/ann_module5.py vendored Normal file
View File

@@ -0,0 +1,10 @@
# Used by test_typing to verify that Final wrapped in ForwardRef works.
from __future__ import annotations
from typing import Final
name: Final[str] = "final"
class MyClass:
value: Final = 3000

7
Lib/test/ann_module6.py vendored Normal file
View File

@@ -0,0 +1,7 @@
# Tests that top-level ClassVar is not allowed
from __future__ import annotations
from typing import ClassVar
wrong: ClassVar[int] = 1

View File

@@ -249,6 +249,15 @@ class TypeVarTests(BaseTestCase):
with self.assertRaises(ValueError):
TypeVar('T', covariant=True, contravariant=True)
def test_bad_var_substitution(self):
T = TypeVar('T')
for arg in (), (int, str):
with self.subTest(arg=arg):
with self.assertRaises(TypeError):
List[T][arg]
with self.assertRaises(TypeError):
list[T][arg]
class UnionTests(BaseTestCase):
@@ -320,6 +329,15 @@ class UnionTests(BaseTestCase):
u = Union[int | float]
self.assertEqual(repr(u), 'typing.Union[int, float]')
u = Union[None, str]
self.assertEqual(repr(u), 'typing.Optional[str]')
u = Union[str, None]
self.assertEqual(repr(u), 'typing.Optional[str]')
u = Union[None, str, int]
self.assertEqual(repr(u), 'typing.Union[NoneType, str, int]')
u = Optional[str]
self.assertEqual(repr(u), 'typing.Optional[str]')
def test_cannot_subclass(self):
with self.assertRaises(TypeError):
class C(Union):
@@ -415,6 +433,8 @@ class TupleTests(BaseTestCase):
class MyTuple(tuple):
pass
self.assertIsSubclass(MyTuple, Tuple)
self.assertIsSubclass(Tuple, Tuple)
self.assertIsSubclass(tuple, Tuple)
def test_tuple_instance_type_error(self):
with self.assertRaises(TypeError):
@@ -442,6 +462,7 @@ class BaseCallableTests:
with self.assertRaises(TypeError):
issubclass(types.FunctionType, Callable[[int], int])
self.assertIsSubclass(types.FunctionType, Callable)
self.assertIsSubclass(Callable, Callable)
def test_eq_hash(self):
Callable = self.Callable
@@ -517,6 +538,10 @@ class BaseCallableTests:
# Shouldn't crash; see https://github.com/python/typing/issues/259
typing.List[Callable[..., str]]
def test_or_and_ror(self):
Callable = self.Callable
self.assertEqual(Callable | Tuple, Union[Callable, Tuple])
self.assertEqual(Tuple | Callable, Union[Tuple, Callable])
def test_basic(self):
Callable = self.Callable
@@ -549,8 +574,11 @@ 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(C2[int, float, str], Callable[[int, float], str])
self.assertEqual(C3[int], Callable[..., int])
self.assertEqual(C3[NoReturn], Callable[..., NoReturn])
# multi chaining
C4 = C2[int, VT, str]
@@ -610,10 +638,31 @@ class BaseCallableTests:
def test_concatenate(self):
Callable = self.Callable
fullname = f"{Callable.__module__}.Callable"
T = TypeVar('T')
P = ParamSpec('P')
C1 = Callable[typing.Concatenate[int, P], int]
self.assertEqual(repr(C1),
f"{fullname}[typing.Concatenate[int, ~P], int]")
P2 = ParamSpec('P2')
C = Callable[Concatenate[int, P], T]
self.assertEqual(repr(C),
f"{fullname}[typing.Concatenate[int, ~P], ~T]")
self.assertEqual(C[P2, int], Callable[Concatenate[int, P2], int])
self.assertEqual(C[[str, float], int], Callable[[int, str, float], int])
self.assertEqual(C[[], int], Callable[[int], int])
self.assertEqual(C[Concatenate[str, P2], int],
Callable[Concatenate[int, str, P2], int])
with self.assertRaises(TypeError):
C[..., int]
C = Callable[Concatenate[int, P], int]
self.assertEqual(repr(C),
f"{fullname}[typing.Concatenate[int, ~P], int]")
self.assertEqual(C[P2], Callable[Concatenate[int, P2], int])
self.assertEqual(C[[str, float]], Callable[[int, str, float], int])
self.assertEqual(C[str, float], Callable[[int, str, float], int])
self.assertEqual(C[[]], Callable[[int], int])
self.assertEqual(C[Concatenate[str, P2]],
Callable[Concatenate[int, str, P2], int])
with self.assertRaises(TypeError):
C[...]
def test_errors(self):
Callable = self.Callable
@@ -652,6 +701,11 @@ class CollectionsCallableTests(BaseCallableTests, BaseTestCase):
def test_paramspec(self): # TODO: RUSTPYTHON, remove when this passes
super().test_paramspec() # TODO: RUSTPYTHON, remove when this passes
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_concatenate(self): # TODO: RUSTPYTHON, remove when this passes
super().test_concatenate() # TODO: RUSTPYTHON, remove when this passes
class LiteralTests(BaseTestCase):
def test_basics(self):
@@ -720,6 +774,8 @@ class LiteralTests(BaseTestCase):
self.assertNotEqual(Literal[True], Literal[1])
self.assertNotEqual(Literal[1], Literal[2])
self.assertNotEqual(Literal[1, True], Literal[1])
self.assertNotEqual(Literal[1, True], Literal[1, 1])
self.assertNotEqual(Literal[1, 2], Literal[True, 2])
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])
@@ -1057,6 +1113,8 @@ class ProtocolTests(BaseTestCase):
with self.assertRaises(TypeError):
issubclass(PG, PG[int])
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_protocols_issubclass_non_callable(self):
class C:
x = 1
@@ -1115,6 +1173,8 @@ class ProtocolTests(BaseTestCase):
with self.assertRaises(TypeError):
isinstance(C(), BadPG)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_protocols_isinstance_py36(self):
class APoint:
def __init__(self, x, y, label):
@@ -1187,6 +1247,8 @@ class ProtocolTests(BaseTestCase):
self.assertIsInstance(D1(), C)
self.assertIsSubclass(D2, C)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_protocols_support_register(self):
@runtime_checkable
class P(Protocol):
@@ -1222,6 +1284,8 @@ class ProtocolTests(BaseTestCase):
self.assertIsInstance(B(), P)
self.assertIsInstance(C(), P)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_none_on_callable_blocks_implementation(self):
@runtime_checkable
class P(Protocol):
@@ -1483,6 +1547,8 @@ class ProtocolTests(BaseTestCase):
class Concrete(Proto):
pass
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_none_treated_correctly(self):
@runtime_checkable
class P(Protocol):
@@ -2659,10 +2725,18 @@ class ForwardRefTests(BaseTestCase):
with self.assertRaises(TypeError):
issubclass(int, fr)
def test_forwardref_only_str_arg(self):
with self.assertRaises(TypeError):
typing.ForwardRef(1) # only `str` type is allowed
def test_forward_equality(self):
fr = typing.ForwardRef('int')
self.assertEqual(fr, typing.ForwardRef('int'))
self.assertNotEqual(List['int'], List[int])
self.assertNotEqual(fr, typing.ForwardRef('int', module=__name__))
frm = typing.ForwardRef('int', module=__name__)
self.assertEqual(frm, typing.ForwardRef('int', module=__name__))
self.assertNotEqual(frm, typing.ForwardRef('int', module='__other_name__'))
def test_forward_equality_gth(self):
c1 = typing.ForwardRef('C')
@@ -2699,6 +2773,14 @@ class ForwardRefTests(BaseTestCase):
self.assertEqual(hash(c1_gth), hash(c2_gth))
self.assertEqual(hash(c1), hash(c1_gth))
c3 = typing.ForwardRef('int', module=__name__)
c4 = typing.ForwardRef('int', module='__other_name__')
self.assertNotEqual(hash(c3), hash(c1))
self.assertNotEqual(hash(c3), hash(c1_gth))
self.assertNotEqual(hash(c3), hash(c4))
self.assertEqual(hash(c3), hash(typing.ForwardRef('int', module=__name__)))
def test_forward_equality_namespace(self):
class A:
pass
@@ -2834,6 +2916,20 @@ class ForwardRefTests(BaseTestCase):
self.assertEqual(get_type_hints(foo, globals(), locals()),
{'a': Callable[..., T]})
def test_special_forms_forward(self):
class C:
a: Annotated['ClassVar[int]', (3, 5)] = 4
b: Annotated['Final[int]', "const"] = 4
class CF:
b: List['Final[int]'] = 4
self.assertEqual(get_type_hints(C, globals())['a'], ClassVar[int])
self.assertEqual(get_type_hints(C, globals())['b'], Final[int])
with self.assertRaises(TypeError):
get_type_hints(CF, globals()),
def test_syntax_error(self):
with self.assertRaises(SyntaxError):
@@ -3030,7 +3126,7 @@ else:
# Definitions needed for features introduced in Python 3.6
from test import ann_module, ann_module2, ann_module3
from test import ann_module, ann_module2, ann_module3, ann_module5, ann_module6
from typing import AsyncContextManager
class A:
@@ -3165,6 +3261,12 @@ class GetTypeHintTests(BaseTestCase):
'my_inner_a2': mod_generics_cache.B.A,
'my_outer_a': mod_generics_cache.A})
def test_get_type_hints_classes_no_implicit_optional(self):
class WithNoneDefault:
field: int = None # most type-checkers won't be happy with it
self.assertEqual(gth(WithNoneDefault), {'field': int})
def test_respect_no_type_check(self):
@no_type_check
class NoTpCheck:
@@ -3281,6 +3383,15 @@ class GetTypeHintTests(BaseTestCase):
{"x": typing.Annotated[int | float, "const"]}
)
def test_get_type_hints_annotated_in_union(self): # bpo-46603
def with_union(x: int | list[Annotated[str, 'meta']]): ...
self.assertEqual(get_type_hints(with_union), {'x': int | list[str]})
self.assertEqual(
get_type_hints(with_union, include_extras=True),
{'x': int | list[Annotated[str, 'meta']]},
)
def test_get_type_hints_annotated_refs(self):
Const = Annotated[T, "Const"]
@@ -3396,6 +3507,22 @@ class GetUtilitiesTestCase(TestCase):
(Concatenate[int, P], int))
self.assertEqual(get_args(list | str), (list, str))
def test_forward_ref_and_final(self):
# https://bugs.python.org/issue45166
hints = get_type_hints(ann_module5)
self.assertEqual(hints, {'name': Final[str]})
hints = get_type_hints(ann_module5.MyClass)
self.assertEqual(hints, {'value': Final})
def test_top_level_class_var(self):
# https://bugs.python.org/issue45166
with self.assertRaisesRegex(
TypeError,
r'typing.ClassVar\[int\] is not valid as type argument',
):
get_type_hints(ann_module6)
class CollectionsAbcTests(BaseTestCase):
@@ -3476,11 +3603,10 @@ class CollectionsAbcTests(BaseTestCase):
self.assertNotIsInstance(42, typing.Container)
def test_collection(self):
if hasattr(typing, 'Collection'):
self.assertIsInstance(tuple(), typing.Collection)
self.assertIsInstance(frozenset(), typing.Collection)
self.assertIsSubclass(dict, typing.Collection)
self.assertNotIsInstance(42, typing.Collection)
self.assertIsInstance(tuple(), typing.Collection)
self.assertIsInstance(frozenset(), typing.Collection)
self.assertIsSubclass(dict, typing.Collection)
self.assertNotIsInstance(42, typing.Collection)
def test_abstractset(self):
self.assertIsInstance(set(), typing.AbstractSet)
@@ -3877,6 +4003,10 @@ class CollectionsAbcTests(BaseTestCase):
A.register(B)
self.assertIsSubclass(B, typing.Mapping)
def test_or_and_ror(self):
self.assertEqual(typing.Sized | typing.Awaitable, Union[typing.Sized, typing.Awaitable])
self.assertEqual(typing.Coroutine | typing.Hashable, Union[typing.Coroutine, typing.Hashable])
class OtherABCTests(BaseTestCase):
@@ -4132,6 +4262,19 @@ class NamedTupleTests(BaseTestCase):
self.assertEqual(a.typename, 'foo')
self.assertEqual(a.fields, [('bar', tuple)])
def test_empty_namedtuple(self):
NT = NamedTuple('NT')
class CNT(NamedTuple):
pass # empty body
for struct in [NT, CNT]:
with self.subTest(struct=struct):
self.assertEqual(struct._fields, ())
self.assertEqual(struct._field_defaults, {})
self.assertEqual(struct.__annotations__, {})
self.assertIsInstance(struct(), struct)
def test_namedtuple_errors(self):
with self.assertRaises(TypeError):
NamedTuple.__new__()
@@ -4327,6 +4470,93 @@ class TypedDictTests(BaseTestCase):
'voice': str,
}
def test_multiple_inheritance(self):
class One(TypedDict):
one: int
class Two(TypedDict):
two: str
class Untotal(TypedDict, total=False):
untotal: str
Inline = TypedDict('Inline', {'inline': bool})
class Regular:
pass
class Child(One, Two):
child: bool
self.assertEqual(
Child.__required_keys__,
frozenset(['one', 'two', 'child']),
)
self.assertEqual(
Child.__optional_keys__,
frozenset([]),
)
self.assertEqual(
Child.__annotations__,
{'one': int, 'two': str, 'child': bool},
)
class ChildWithOptional(One, Untotal):
child: bool
self.assertEqual(
ChildWithOptional.__required_keys__,
frozenset(['one', 'child']),
)
self.assertEqual(
ChildWithOptional.__optional_keys__,
frozenset(['untotal']),
)
self.assertEqual(
ChildWithOptional.__annotations__,
{'one': int, 'untotal': str, 'child': bool},
)
class ChildWithTotalFalse(One, Untotal, total=False):
child: bool
self.assertEqual(
ChildWithTotalFalse.__required_keys__,
frozenset(['one']),
)
self.assertEqual(
ChildWithTotalFalse.__optional_keys__,
frozenset(['untotal', 'child']),
)
self.assertEqual(
ChildWithTotalFalse.__annotations__,
{'one': int, 'untotal': str, 'child': bool},
)
class ChildWithInlineAndOptional(Untotal, Inline):
child: bool
self.assertEqual(
ChildWithInlineAndOptional.__required_keys__,
frozenset(['inline', 'child']),
)
self.assertEqual(
ChildWithInlineAndOptional.__optional_keys__,
frozenset(['untotal']),
)
self.assertEqual(
ChildWithInlineAndOptional.__annotations__,
{'inline': bool, 'untotal': str, 'child': bool},
)
wrong_bases = [
(One, Regular),
(Regular, One),
(One, Two, Regular),
(Inline, Regular),
(Untotal, Regular),
]
for bases in wrong_bases:
with self.subTest(bases=bases):
with self.assertRaisesRegex(
TypeError,
'cannot inherit from both a TypedDict type and a non-TypedDict',
):
class Wrong(*bases):
pass
def test_is_typeddict(self):
assert is_typeddict(Point2D) is True
assert is_typeddict(Union[str, int]) is False
@@ -4339,6 +4569,21 @@ class TypedDictTests(BaseTestCase):
{'a': typing.Optional[int], 'b': int}
)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_non_generic_subscript(self):
# For backward compatibility, subscription works
# on arbitrary TypedDict types.
class TD(TypedDict):
a: T
A = TD[int]
self.assertEqual(A.__origin__, TD)
self.assertEqual(A.__parameters__, ())
self.assertEqual(A.__args__, (int,))
a = A(a = 1)
self.assertIs(type(a), dict)
self.assertEqual(a, {'a': 1})
class IOTests(BaseTestCase):
@@ -4439,6 +4684,13 @@ class RETests(BaseTestCase):
class AnnotatedTests(BaseTestCase):
def test_new(self):
with self.assertRaisesRegex(
TypeError,
'Type Annotated cannot be instantiated',
):
Annotated()
def test_repr(self):
self.assertEqual(
repr(Annotated[int, 4, 5]),
@@ -4523,6 +4775,14 @@ class AnnotatedTests(BaseTestCase):
A.x = 5
self.assertEqual(C.x, 5)
def test_special_form_containment(self):
class C:
classvar: Annotated[ClassVar[int], "a decoration"] = 4
const: Annotated[Final[int], "Const"] = 4
self.assertEqual(get_type_hints(C, globals())['classvar'], ClassVar[int])
self.assertEqual(get_type_hints(C, globals())['const'], Final[int])
def test_hash_eq(self):
self.assertEqual(len({Annotated[int, 4, 5], Annotated[int, 4, 5]}), 1)
self.assertNotEqual(Annotated[int, 4, 5], Annotated[int, 5, 4])
@@ -4546,6 +4806,10 @@ class AnnotatedTests(BaseTestCase):
with self.assertRaises(TypeError):
issubclass(int, Annotated[int, "positive"])
def test_too_few_type_args(self):
with self.assertRaisesRegex(TypeError, 'at least two arguments'):
Annotated[int]
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_pickle(self):
@@ -4632,6 +4896,11 @@ class TypeAliasTests(BaseTestCase):
with self.assertRaises(TypeError):
isinstance(42, TypeAlias)
def test_stringized_usage(self):
class A:
a: "TypeAlias"
self.assertEqual(get_type_hints(A), {'a': TypeAlias})
def test_no_issubclass(self):
with self.assertRaises(TypeError):
issubclass(Employee, TypeAlias)
@@ -4682,15 +4951,35 @@ class ParamSpecTests(BaseTestCase):
def test_args_kwargs(self):
P = ParamSpec('P')
P_2 = ParamSpec('P_2')
self.assertIn('args', dir(P))
self.assertIn('kwargs', dir(P))
self.assertIsInstance(P.args, ParamSpecArgs)
self.assertIsInstance(P.kwargs, ParamSpecKwargs)
self.assertIs(P.args.__origin__, P)
self.assertIs(P.kwargs.__origin__, P)
self.assertEqual(P.args, P.args)
self.assertEqual(P.kwargs, P.kwargs)
self.assertNotEqual(P.args, P_2.args)
self.assertNotEqual(P.kwargs, P_2.kwargs)
self.assertNotEqual(P.args, P.kwargs)
self.assertNotEqual(P.kwargs, P.args)
self.assertNotEqual(P.args, P_2.kwargs)
self.assertEqual(repr(P.args), "P.args")
self.assertEqual(repr(P.kwargs), "P.kwargs")
def test_stringized(self):
P = ParamSpec('P')
class C(Generic[P]):
func: Callable["P", int]
def foo(self, *args: "P.args", **kwargs: "P.kwargs"):
pass
self.assertEqual(gth(C, globals(), locals()), {"func": Callable[P, int]})
self.assertEqual(
gth(C.foo, globals(), locals()), {"args": P.args, "kwargs": P.kwargs}
)
def test_user_generics(self):
T = TypeVar("T")
P = ParamSpec("P")
@@ -4759,6 +5048,17 @@ class ParamSpecTests(BaseTestCase):
self.assertEqual(G1.__args__, ((int, str), (bytes,)))
self.assertEqual(G2.__args__, ((int,), (str, bytes)))
def test_bad_var_substitution(self):
T = TypeVar('T')
P = ParamSpec('P')
bad_args = (42, int, None, T, int|str, Union[int, str])
for arg in bad_args:
with self.subTest(arg=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
@@ -4788,6 +5088,31 @@ class ParamSpecTests(BaseTestCase):
self.assertEqual(G1.__parameters__, (P, T))
self.assertEqual(G2.__parameters__, (P, T))
self.assertEqual(G3.__parameters__, (P, T))
C = Callable[[int, str], float]
self.assertEqual(G1[[int, str], float], List[C])
self.assertEqual(G2[[int, str], float], list[C])
self.assertEqual(G3[[int, str], float], list[C] | int)
def test_paramspec_gets_copied(self):
# bpo-46581
P = ParamSpec('P')
P2 = ParamSpec('P2')
C1 = Callable[P, int]
self.assertEqual(C1.__parameters__, (P,))
self.assertEqual(C1[P2].__parameters__, (P2,))
self.assertEqual(C1[str].__parameters__, ())
self.assertEqual(C1[str, T].__parameters__, (T,))
self.assertEqual(C1[Concatenate[str, P2]].__parameters__, (P2,))
self.assertEqual(C1[Concatenate[T, P2]].__parameters__, (T, P2))
self.assertEqual(C1[...].__parameters__, ())
C2 = Callable[Concatenate[str, P], int]
self.assertEqual(C2.__parameters__, (P,))
self.assertEqual(C2[P2].__parameters__, (P2,))
self.assertEqual(C2[str].__parameters__, ())
self.assertEqual(C2[str, T].__parameters__, (T,))
self.assertEqual(C2[Concatenate[str, P2]].__parameters__, (P2,))
self.assertEqual(C2[Concatenate[T, P2]].__parameters__, (T, P2))
class ConcatenateTests(BaseTestCase):
@@ -4815,6 +5140,27 @@ class ConcatenateTests(BaseTestCase):
self.assertEqual(C4.__args__, (Concatenate[int, T, P], T))
self.assertEqual(C4.__parameters__, (T, P))
def test_var_substitution(self):
T = TypeVar('T')
P = ParamSpec('P')
P2 = ParamSpec('P2')
C = Concatenate[T, P]
self.assertEqual(C[int, P2], Concatenate[int, P2])
self.assertEqual(C[int, [str, float]], (int, str, float))
self.assertEqual(C[int, []], (int,))
self.assertEqual(C[int, Concatenate[str, P2]],
Concatenate[int, str, P2])
with self.assertRaises(TypeError):
C[int, ...]
C = Concatenate[int, P]
self.assertEqual(C[P2], Concatenate[int, P2])
self.assertEqual(C[[str, float]], (int, str, float))
self.assertEqual(C[str, float], (int, str, float))
self.assertEqual(C[[]], (int,))
self.assertEqual(C[Concatenate[str, P2]], Concatenate[int, str, P2])
with self.assertRaises(TypeError):
C[...]
class TypeGuardTests(BaseTestCase):
def test_basics(self):
@@ -4963,6 +5309,8 @@ class SpecialAttrsTests(BaseTestCase):
typing.Concatenate[Any, SpecialAttrsP]: 'Concatenate',
typing.Final[Any]: 'Final',
typing.Literal[Any]: 'Literal',
typing.Literal[1, 2]: 'Literal',
typing.Literal[True, 2]: 'Literal',
typing.Optional[Any]: 'Optional',
typing.TypeGuard[Any]: 'TypeGuard',
typing.Union[Any]: 'Any',
@@ -5008,7 +5356,7 @@ class SpecialAttrsTests(BaseTestCase):
)
self.assertEqual(
SpecialAttrsTests.TypeName.__module__,
'test.test_typing',
__name__,
)
# NewTypes are picklable assuming correct qualname information.
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
@@ -5022,7 +5370,7 @@ class SpecialAttrsTests(BaseTestCase):
# __qualname__ is unnecessary.
self.assertEqual(SpecialAttrsT.__name__, 'SpecialAttrsT')
self.assertFalse(hasattr(SpecialAttrsT, '__qualname__'))
self.assertEqual(SpecialAttrsT.__module__, 'test.test_typing')
self.assertEqual(SpecialAttrsT.__module__, __name__)
# Module-level type variables are picklable.
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
s = pickle.dumps(SpecialAttrsT, proto)
@@ -5031,13 +5379,24 @@ class SpecialAttrsTests(BaseTestCase):
self.assertEqual(SpecialAttrsP.__name__, 'SpecialAttrsP')
self.assertFalse(hasattr(SpecialAttrsP, '__qualname__'))
self.assertEqual(SpecialAttrsP.__module__, 'test.test_typing')
self.assertEqual(SpecialAttrsP.__module__, __name__)
# Module-level ParamSpecs are picklable.
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
s = pickle.dumps(SpecialAttrsP, proto)
loaded = pickle.loads(s)
self.assertIs(SpecialAttrsP, loaded)
def test_genericalias_dir(self):
class Foo(Generic[T]):
def bar(self):
pass
baz = 3
# The class attributes of the original class should be visible even
# in dir() of the GenericAlias. See bpo-45755.
self.assertIn('bar', dir(Foo[int]))
self.assertIn('baz', dir(Foo[int]))
class AllTests(BaseTestCase):
"""Tests for __all__."""
@@ -5048,8 +5407,9 @@ class AllTests(BaseTestCase):
self.assertIn('ValuesView', a)
self.assertIn('cast', a)
self.assertIn('overload', a)
if hasattr(contextlib, 'AbstractContextManager'):
self.assertIn('ContextManager', a)
# Context managers.
self.assertIn('ContextManager', a)
self.assertIn('AsyncContextManager', a)
# Check that io and re are not exported.
self.assertNotIn('io', a)
self.assertNotIn('re', a)
@@ -5063,7 +5423,6 @@ class AllTests(BaseTestCase):
self.assertIn('SupportsComplex', a)
def test_all_exported_names(self):
import typing
actual_all = set(typing.__all__)
computed_all = {

107
Lib/typing.py vendored
View File

@@ -134,16 +134,16 @@ __all__ = [
# legitimate imports of those modules.
def _type_convert(arg, module=None):
def _type_convert(arg, module=None, *, allow_special_forms=False):
"""For converting None to type(None), and strings to ForwardRef."""
if arg is None:
return type(None)
if isinstance(arg, str):
return ForwardRef(arg, module=module)
return ForwardRef(arg, module=module, is_class=allow_special_forms)
return arg
def _type_check(arg, msg, is_argument=True, module=None):
def _type_check(arg, msg, is_argument=True, module=None, *, allow_special_forms=False):
"""Check that the argument is a type, and return it (internal helper).
As a special case, accept None and return type(None) instead. Also wrap strings
@@ -156,18 +156,21 @@ def _type_check(arg, msg, is_argument=True, module=None):
We append the repr() of the actual value (truncated to 100 chars).
"""
invalid_generic_forms = (Generic, Protocol)
if is_argument:
invalid_generic_forms = invalid_generic_forms + (ClassVar, Final)
if not allow_special_forms:
invalid_generic_forms += (ClassVar,)
if is_argument:
invalid_generic_forms += (Final,)
arg = _type_convert(arg, module=module)
arg = _type_convert(arg, module=module, allow_special_forms=allow_special_forms)
if (isinstance(arg, _GenericAlias) and
arg.__origin__ in invalid_generic_forms):
raise TypeError(f"{arg} is not valid as type argument")
if arg in (Any, NoReturn):
if arg in (Any, NoReturn, Final, TypeAlias):
return arg
if isinstance(arg, _SpecialForm) or arg in (Generic, Protocol):
raise TypeError(f"Plain {arg} is not valid as type argument")
if isinstance(arg, (type, TypeVar, ForwardRef, types.UnionType, ParamSpec)):
if isinstance(arg, (type, TypeVar, ForwardRef, types.UnionType, ParamSpec,
ParamSpecArgs, ParamSpecKwargs)):
return arg
if not callable(arg):
raise TypeError(f"{msg} Got {arg!r:.100}.")
@@ -317,8 +320,8 @@ def _tp_cache(func=None, /, *, typed=False):
def _eval_type(t, globalns, localns, recursive_guard=frozenset()):
"""Evaluate all forward references in the given type t.
For use of globalns and localns see the docstring for get_type_hints().
recursive_guard is used to prevent prevent infinite recursion
with recursive ForwardRef.
recursive_guard is used to prevent infinite recursion with a recursive
ForwardRef.
"""
if isinstance(t, ForwardRef):
return t._evaluate(globalns, localns, recursive_guard)
@@ -401,9 +404,10 @@ class _SpecialForm(_Final, _root=True):
class _LiteralSpecialForm(_SpecialForm, _root=True):
@_tp_cache(typed=True)
def __getitem__(self, parameters):
return self._getitem(self, parameters)
if not isinstance(parameters, tuple):
parameters = (parameters,)
return self._getitem(self, *parameters)
@_SpecialForm
@@ -526,7 +530,8 @@ def Optional(self, parameters):
return Union[arg, type(None)]
@_LiteralSpecialForm
def Literal(self, parameters):
@_tp_cache(typed=True)
def Literal(self, *parameters):
"""Special typing form to define literal types (a.k.a. value types).
This form can be used to indicate to type checkers that the corresponding
@@ -549,9 +554,6 @@ def Literal(self, parameters):
"""
# There is no '_type_check' call because arguments to Literal[...] are
# values, not types.
if not isinstance(parameters, tuple):
parameters = (parameters,)
parameters = _flatten_literal_params(parameters)
try:
@@ -597,8 +599,10 @@ def Concatenate(self, parameters):
raise TypeError("The last parameter to Concatenate should be a "
"ParamSpec variable.")
msg = "Concatenate[arg, ...]: each arg must be a type."
parameters = tuple(_type_check(p, msg) for p in parameters)
return _ConcatenateGenericAlias(self, parameters)
parameters = (*(_type_check(p, msg) for p in parameters[:-1]), parameters[-1])
return _ConcatenateGenericAlias(self, parameters,
_typevar_types=(TypeVar, ParamSpec),
_paramspec_tvars=True)
@_SpecialForm
@@ -654,9 +658,10 @@ class ForwardRef(_Final, _root=True):
__slots__ = ('__forward_arg__', '__forward_code__',
'__forward_evaluated__', '__forward_value__',
'__forward_is_argument__', '__forward_module__')
'__forward_is_argument__', '__forward_is_class__',
'__forward_module__')
def __init__(self, arg, is_argument=True, module=None):
def __init__(self, arg, is_argument=True, module=None, *, is_class=False):
if not isinstance(arg, str):
raise TypeError(f"Forward reference must be a string -- got {arg!r}")
try:
@@ -668,6 +673,7 @@ class ForwardRef(_Final, _root=True):
self.__forward_evaluated__ = False
self.__forward_value__ = None
self.__forward_is_argument__ = is_argument
self.__forward_is_class__ = is_class
self.__forward_module__ = module
def _evaluate(self, globalns, localns, recursive_guard):
@@ -684,10 +690,11 @@ class ForwardRef(_Final, _root=True):
globalns = getattr(
sys.modules.get(self.__forward_module__, None), '__dict__', globalns
)
type_ =_type_check(
type_ = _type_check(
eval(self.__forward_code__, globalns, localns),
"Forward references must evaluate to types.",
is_argument=self.__forward_is_argument__,
allow_special_forms=self.__forward_is_class__,
)
self.__forward_value__ = _eval_type(
type_, globalns, localns, recursive_guard | {self.__forward_arg__}
@@ -701,10 +708,11 @@ class ForwardRef(_Final, _root=True):
if self.__forward_evaluated__ and other.__forward_evaluated__:
return (self.__forward_arg__ == other.__forward_arg__ and
self.__forward_value__ == other.__forward_value__)
return self.__forward_arg__ == other.__forward_arg__
return (self.__forward_arg__ == other.__forward_arg__ and
self.__forward_module__ == other.__forward_module__)
def __hash__(self):
return hash(self.__forward_arg__)
return hash((self.__forward_arg__, self.__forward_module__))
def __repr__(self):
return f'ForwardRef({self.__forward_arg__!r})'
@@ -826,6 +834,11 @@ class ParamSpecArgs(_Final, _Immutable, _root=True):
def __repr__(self):
return f"{self.__origin__.__name__}.args"
def __eq__(self, other):
if not isinstance(other, ParamSpecArgs):
return NotImplemented
return self.__origin__ == other.__origin__
class ParamSpecKwargs(_Final, _Immutable, _root=True):
"""The kwargs for a ParamSpec object.
@@ -845,6 +858,11 @@ class ParamSpecKwargs(_Final, _Immutable, _root=True):
def __repr__(self):
return f"{self.__origin__.__name__}.kwargs"
def __eq__(self, other):
if not isinstance(other, ParamSpecKwargs):
return NotImplemented
return self.__origin__ == other.__origin__
class ParamSpec(_Final, _Immutable, _TypeVarLike, _root=True):
"""Parameter specification variable.
@@ -857,7 +875,7 @@ class ParamSpec(_Final, _Immutable, _TypeVarLike, _root=True):
type checkers. They are used to forward the parameter types of one
callable to another callable, a pattern commonly found in higher order
functions and decorators. They are only valid when used in ``Concatenate``,
or s the first argument to ``Callable``, or as parameters for user-defined
or as the first argument to ``Callable``, or as parameters for user-defined
Generics. See class Generic for more information on generic types. An
example for annotating a decorator::
@@ -960,7 +978,7 @@ class _BaseGenericAlias(_Final, _root=True):
return self._name or self.__origin__.__name__
# We are careful for copy and pickle.
# Also for simplicity we just don't relay all dunder names
# Also for simplicity we don't relay any dunder names
if '__origin__' in self.__dict__ and not _is_dunder(attr):
return getattr(self.__origin__, attr)
raise AttributeError(attr)
@@ -979,6 +997,9 @@ class _BaseGenericAlias(_Final, _root=True):
raise TypeError("Subscripted generics cannot be used with"
" class and instance checks")
def __dir__(self):
return list(set(super().__dir__()
+ [attr for attr in dir(self.__origin__) if not _is_dunder(attr)]))
# Special typing constructs Union, Optional, Generic, Callable and Tuple
# use three special attributes for internal bookkeeping of generic types:
@@ -1060,7 +1081,9 @@ class _GenericAlias(_BaseGenericAlias, _root=True):
return self.copy_with(tuple(new_args))
def copy_with(self, params):
return self.__class__(self.__origin__, params, name=self._name, inst=self._inst)
return self.__class__(self.__origin__, params, name=self._name, inst=self._inst,
_typevar_types=self._typevar_types,
_paramspec_tvars=self._paramspec_tvars)
def __repr__(self):
if self._name:
@@ -1262,10 +1285,15 @@ class _LiteralGenericAlias(_GenericAlias, _root=True):
class _ConcatenateGenericAlias(_GenericAlias, _root=True):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs,
_typevar_types=(TypeVar, ParamSpec),
_paramspec_tvars=True)
def copy_with(self, params):
if isinstance(params[-1], (list, tuple)):
return (*params[:-1], *params[-1])
if isinstance(params[-1], _ConcatenateGenericAlias):
params = (*params[:-1], *params[-1].__args__)
elif not isinstance(params[-1], ParamSpec):
raise TypeError("The last parameter to Concatenate should be a "
"ParamSpec variable.")
return super().copy_with(params)
class Generic:
@@ -1441,9 +1469,7 @@ def _allow_reckless_class_checks(depth=3):
issubclass() on the whole MRO of a user class, which may contain protocols.
"""
try:
# XXX RUSTPYTHON: added _py_abc; I think CPython was fine because abc called
# directly into the _abc builtin module, which wasn't in the frame stack
return sys._getframe(3).f_globals['__name__'] in ['abc', 'functools', '_py_abc']
return sys._getframe(depth).f_globals['__name__'] in ['abc', 'functools']
except (AttributeError, ValueError): # For platforms without _getframe().
return True
@@ -1672,7 +1698,7 @@ class Annotated:
"with at least two arguments (a type and an "
"annotation).")
msg = "Annotated[t, ...]: t must be a type."
origin = _type_check(params[0], msg)
origin = _type_check(params[0], msg, allow_special_forms=True)
metadata = tuple(params[1:])
return _AnnotatedAlias(origin, metadata)
@@ -1802,7 +1828,7 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False):
if value is None:
value = type(None)
if isinstance(value, str):
value = ForwardRef(value, is_argument=False)
value = ForwardRef(value, is_argument=False, is_class=True)
value = _eval_type(value, base_globals, base_locals)
hints[name] = value
return hints if include_extras else {k: _strip_annotations(t) for k, t in hints.items()}
@@ -1834,7 +1860,13 @@ def get_type_hints(obj, globalns=None, localns=None, include_extras=False):
if value is None:
value = type(None)
if isinstance(value, str):
value = ForwardRef(value)
# class-level forward refs were handled above, this must be either
# a module-level annotation or a function argument annotation
value = ForwardRef(
value,
is_argument=not isinstance(obj, types.ModuleType),
is_class=False,
)
value = _eval_type(value, globalns, localns)
if name in defaults and defaults[name] is None:
value = Optional[value]
@@ -2423,7 +2455,7 @@ class NewType:
"""NewType creates simple unique types with almost zero
runtime overhead. NewType(name, tp) is considered a subtype of tp
by static type checkers. At runtime, NewType(name, tp) returns
a dummy function that simply returns its argument. Usage::
a dummy callable that simply returns its argument. Usage::
UserId = NewType('UserId', int)
@@ -2628,6 +2660,7 @@ class io:
TextIO = TextIO
BinaryIO = BinaryIO
io.__name__ = __name__ + '.io'
sys.modules[io.__name__] = io