mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-09 22:49:57 +09:00
Merge pull request #3877 from moreal/update-typing-3105
Update `typing` module to 3.10.5
This commit is contained in:
10
Lib/test/ann_module5.py
vendored
Normal file
10
Lib/test/ann_module5.py
vendored
Normal 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
7
Lib/test/ann_module6.py
vendored
Normal 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
|
||||
389
Lib/test/test_typing.py
vendored
389
Lib/test/test_typing.py
vendored
@@ -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
107
Lib/typing.py
vendored
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user