bpo-32226: PEP 560: improve typing module (#4906)
This PR re-designs the internal typing API using the new PEP 560 features. However, there are only few minor changes in the public API.
This commit is contained in:
parent
d57f26c753
commit
d911e40e78
|
@ -389,7 +389,8 @@ def _get_field(cls, a_name, a_type):
|
||||||
if typing is not None:
|
if typing is not None:
|
||||||
# This test uses a typing internal class, but it's the best
|
# This test uses a typing internal class, but it's the best
|
||||||
# way to test if this is a ClassVar.
|
# way to test if this is a ClassVar.
|
||||||
if type(a_type) is typing._ClassVar:
|
if (type(a_type) is typing._GenericAlias and
|
||||||
|
a_type.__origin__ is typing.ClassVar):
|
||||||
# This field is a ClassVar, so it's not a field.
|
# This field is a ClassVar, so it's not a field.
|
||||||
f._field_type = _FIELD_CLASSVAR
|
f._field_type = _FIELD_CLASSVAR
|
||||||
|
|
||||||
|
|
|
@ -135,11 +135,6 @@ def dash_R_cleanup(fs, ps, pic, zdc, abcs):
|
||||||
# Clear ABC registries, restoring previously saved ABC registries.
|
# Clear ABC registries, restoring previously saved ABC registries.
|
||||||
abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__]
|
abs_classes = [getattr(collections.abc, a) for a in collections.abc.__all__]
|
||||||
abs_classes = filter(isabstract, abs_classes)
|
abs_classes = filter(isabstract, abs_classes)
|
||||||
if 'typing' in sys.modules:
|
|
||||||
t = sys.modules['typing']
|
|
||||||
# These classes require special treatment because they do not appear
|
|
||||||
# in direct subclasses of collections.abc classes
|
|
||||||
abs_classes = list(abs_classes) + [t.ChainMap, t.Counter, t.DefaultDict]
|
|
||||||
for abc in abs_classes:
|
for abc in abs_classes:
|
||||||
for obj in abc.__subclasses__() + [abc]:
|
for obj in abc.__subclasses__() + [abc]:
|
||||||
obj._abc_registry = abcs.get(obj, WeakSet()).copy()
|
obj._abc_registry = abcs.get(obj, WeakSet()).copy()
|
||||||
|
|
|
@ -827,7 +827,7 @@ class TestDescriptions(unittest.TestCase):
|
||||||
'f\x08fo\x08oo\x08o(data: List[Any], x: int)'
|
'f\x08fo\x08oo\x08o(data: List[Any], x: int)'
|
||||||
' -> Iterator[Tuple[int, Any]]')
|
' -> Iterator[Tuple[int, Any]]')
|
||||||
self.assertEqual(pydoc.render_doc(C).splitlines()[2],
|
self.assertEqual(pydoc.render_doc(C).splitlines()[2],
|
||||||
'class C\x08C(typing.Mapping)')
|
'class C\x08C(collections.abc.Mapping, typing.Generic)')
|
||||||
|
|
||||||
def test_builtin(self):
|
def test_builtin(self):
|
||||||
for name in ('str', 'str.translate', 'builtins.str',
|
for name in ('str', 'str.translate', 'builtins.str',
|
||||||
|
|
|
@ -12,7 +12,7 @@ from typing import T, KT, VT # Not in __all__.
|
||||||
from typing import Union, Optional
|
from typing import Union, Optional
|
||||||
from typing import Tuple, List, MutableMapping
|
from typing import Tuple, List, MutableMapping
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Generic, ClassVar, GenericMeta
|
from typing import Generic, ClassVar
|
||||||
from typing import cast
|
from typing import cast
|
||||||
from typing import get_type_hints
|
from typing import get_type_hints
|
||||||
from typing import no_type_check, no_type_check_decorator
|
from typing import no_type_check, no_type_check_decorator
|
||||||
|
@ -24,20 +24,8 @@ from typing import Pattern, Match
|
||||||
import abc
|
import abc
|
||||||
import typing
|
import typing
|
||||||
import weakref
|
import weakref
|
||||||
try:
|
|
||||||
import collections.abc as collections_abc
|
|
||||||
except ImportError:
|
|
||||||
import collections as collections_abc # Fallback for PY3.2.
|
|
||||||
|
|
||||||
|
from test import mod_generics_cache
|
||||||
try:
|
|
||||||
import mod_generics_cache
|
|
||||||
except ImportError:
|
|
||||||
# try to use the builtin one, Python 3.5+
|
|
||||||
from test import mod_generics_cache
|
|
||||||
|
|
||||||
|
|
||||||
PY36 = sys.version_info[:2] >= (3, 6)
|
|
||||||
|
|
||||||
|
|
||||||
class BaseTestCase(TestCase):
|
class BaseTestCase(TestCase):
|
||||||
|
@ -606,7 +594,10 @@ class GenericTests(BaseTestCase):
|
||||||
Y[str]
|
Y[str]
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
Y[str, str]
|
Y[str, str]
|
||||||
self.assertIsSubclass(SimpleMapping[str, int], SimpleMapping)
|
SM1 = SimpleMapping[str, int]
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
issubclass(SM1, SimpleMapping)
|
||||||
|
self.assertIsInstance(SM1(), SimpleMapping)
|
||||||
|
|
||||||
def test_generic_errors(self):
|
def test_generic_errors(self):
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
|
@ -617,6 +608,8 @@ class GenericTests(BaseTestCase):
|
||||||
Generic[T][T]
|
Generic[T][T]
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
Generic[T][S]
|
Generic[T][S]
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
class C(Generic[T], Generic[T]): ...
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
isinstance([], List[int])
|
isinstance([], List[int])
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
|
@ -636,7 +629,6 @@ class GenericTests(BaseTestCase):
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
Generic[T, S, T]
|
Generic[T, S, T]
|
||||||
|
|
||||||
@skipUnless(PY36, "__init_subclass__ support required")
|
|
||||||
def test_init_subclass(self):
|
def test_init_subclass(self):
|
||||||
class X(typing.Generic[T]):
|
class X(typing.Generic[T]):
|
||||||
def __init_subclass__(cls, **kwargs):
|
def __init_subclass__(cls, **kwargs):
|
||||||
|
@ -659,9 +651,9 @@ class GenericTests(BaseTestCase):
|
||||||
|
|
||||||
def test_repr(self):
|
def test_repr(self):
|
||||||
self.assertEqual(repr(SimpleMapping),
|
self.assertEqual(repr(SimpleMapping),
|
||||||
__name__ + '.' + 'SimpleMapping')
|
"<class 'test.test_typing.SimpleMapping'>")
|
||||||
self.assertEqual(repr(MySimpleMapping),
|
self.assertEqual(repr(MySimpleMapping),
|
||||||
__name__ + '.' + 'MySimpleMapping')
|
"<class 'test.test_typing.MySimpleMapping'>")
|
||||||
|
|
||||||
def test_chain_repr(self):
|
def test_chain_repr(self):
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
|
@ -713,7 +705,7 @@ class GenericTests(BaseTestCase):
|
||||||
def test_new_repr_bare(self):
|
def test_new_repr_bare(self):
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
self.assertEqual(repr(Generic[T]), 'typing.Generic[~T]')
|
self.assertEqual(repr(Generic[T]), 'typing.Generic[~T]')
|
||||||
self.assertEqual(repr(typing._Protocol[T]), 'typing.Protocol[~T]')
|
self.assertEqual(repr(typing._Protocol[T]), 'typing._Protocol[~T]')
|
||||||
class C(typing.Dict[Any, Any]): ...
|
class C(typing.Dict[Any, Any]): ...
|
||||||
# this line should just work
|
# this line should just work
|
||||||
repr(C.__mro__)
|
repr(C.__mro__)
|
||||||
|
@ -764,11 +756,13 @@ class GenericTests(BaseTestCase):
|
||||||
|
|
||||||
def test_abc_registry_kept(self):
|
def test_abc_registry_kept(self):
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
class C(Generic[T]): ...
|
class C(collections.abc.Mapping, Generic[T]): ...
|
||||||
C.register(int)
|
C.register(int)
|
||||||
self.assertIsInstance(1, C)
|
self.assertIsInstance(1, C)
|
||||||
C[int]
|
C[int]
|
||||||
self.assertIsInstance(1, C)
|
self.assertIsInstance(1, C)
|
||||||
|
C._abc_registry.clear()
|
||||||
|
C._abc_cache.clear() # To keep refleak hunting mode clean
|
||||||
|
|
||||||
def test_false_subclasses(self):
|
def test_false_subclasses(self):
|
||||||
class MyMapping(MutableMapping[str, str]): pass
|
class MyMapping(MutableMapping[str, str]): pass
|
||||||
|
@ -789,18 +783,17 @@ class GenericTests(BaseTestCase):
|
||||||
return 0
|
return 0
|
||||||
# this should just work
|
# this should just work
|
||||||
MM().update()
|
MM().update()
|
||||||
self.assertIsInstance(MM(), collections_abc.MutableMapping)
|
self.assertIsInstance(MM(), collections.abc.MutableMapping)
|
||||||
self.assertIsInstance(MM(), MutableMapping)
|
self.assertIsInstance(MM(), MutableMapping)
|
||||||
self.assertNotIsInstance(MM(), List)
|
self.assertNotIsInstance(MM(), List)
|
||||||
self.assertNotIsInstance({}, MM)
|
self.assertNotIsInstance({}, MM)
|
||||||
|
|
||||||
def test_multiple_bases(self):
|
def test_multiple_bases(self):
|
||||||
class MM1(MutableMapping[str, str], collections_abc.MutableMapping):
|
class MM1(MutableMapping[str, str], collections.abc.MutableMapping):
|
||||||
pass
|
pass
|
||||||
with self.assertRaises(TypeError):
|
class MM2(collections.abc.MutableMapping, MutableMapping[str, str]):
|
||||||
# consistent MRO not possible
|
pass
|
||||||
class MM2(collections_abc.MutableMapping, MutableMapping[str, str]):
|
self.assertEqual(MM2.__bases__, (collections.abc.MutableMapping, Generic))
|
||||||
pass
|
|
||||||
|
|
||||||
def test_orig_bases(self):
|
def test_orig_bases(self):
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
|
@ -855,16 +848,17 @@ class GenericTests(BaseTestCase):
|
||||||
self.assertEqual(D[int].__parameters__, ())
|
self.assertEqual(D[int].__parameters__, ())
|
||||||
self.assertEqual(C[int].__args__, (int,))
|
self.assertEqual(C[int].__args__, (int,))
|
||||||
self.assertEqual(D[int].__args__, (int,))
|
self.assertEqual(D[int].__args__, (int,))
|
||||||
self.assertEqual(C.__bases__, (List,))
|
self.assertEqual(C.__bases__, (list, Generic))
|
||||||
self.assertEqual(D.__bases__, (C, List))
|
self.assertEqual(D.__bases__, (C, list, Generic))
|
||||||
self.assertEqual(C.__orig_bases__, (List[T][U][V],))
|
self.assertEqual(C.__orig_bases__, (List[T][U][V],))
|
||||||
self.assertEqual(D.__orig_bases__, (C, List[T][U][V]))
|
self.assertEqual(D.__orig_bases__, (C, List[T][U][V]))
|
||||||
|
|
||||||
def test_subscript_meta(self):
|
def test_subscript_meta(self):
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
self.assertEqual(Type[GenericMeta], Type[GenericMeta])
|
class Meta(type): ...
|
||||||
self.assertEqual(Union[T, int][GenericMeta], Union[GenericMeta, int])
|
self.assertEqual(Type[Meta], Type[Meta])
|
||||||
self.assertEqual(Callable[..., GenericMeta].__args__, (Ellipsis, GenericMeta))
|
self.assertEqual(Union[T, int][Meta], Union[Meta, int])
|
||||||
|
self.assertEqual(Callable[..., Meta].__args__, (Ellipsis, Meta))
|
||||||
|
|
||||||
def test_generic_hashes(self):
|
def test_generic_hashes(self):
|
||||||
class A(Generic[T]):
|
class A(Generic[T]):
|
||||||
|
@ -939,7 +933,7 @@ class GenericTests(BaseTestCase):
|
||||||
self.assertEqual(repr(Union[Tuple, Callable]).replace('typing.', ''),
|
self.assertEqual(repr(Union[Tuple, Callable]).replace('typing.', ''),
|
||||||
'Union[Tuple, Callable]')
|
'Union[Tuple, Callable]')
|
||||||
self.assertEqual(repr(Union[Tuple, Tuple[int]]).replace('typing.', ''),
|
self.assertEqual(repr(Union[Tuple, Tuple[int]]).replace('typing.', ''),
|
||||||
'Tuple')
|
'Union[Tuple, Tuple[int]]')
|
||||||
self.assertEqual(repr(Callable[..., Optional[T]][int]).replace('typing.', ''),
|
self.assertEqual(repr(Callable[..., Optional[T]][int]).replace('typing.', ''),
|
||||||
'Callable[..., Union[int, NoneType]]')
|
'Callable[..., Union[int, NoneType]]')
|
||||||
self.assertEqual(repr(Callable[[], List[T]][int]).replace('typing.', ''),
|
self.assertEqual(repr(Callable[[], List[T]][int]).replace('typing.', ''),
|
||||||
|
@ -980,13 +974,15 @@ class GenericTests(BaseTestCase):
|
||||||
|
|
||||||
self.assertEqual(repr(C1[int]).split('.')[-1], 'C1[int]')
|
self.assertEqual(repr(C1[int]).split('.')[-1], 'C1[int]')
|
||||||
self.assertEqual(C2.__parameters__, ())
|
self.assertEqual(C2.__parameters__, ())
|
||||||
self.assertIsInstance(C2(), collections_abc.Callable)
|
self.assertIsInstance(C2(), collections.abc.Callable)
|
||||||
self.assertIsSubclass(C2, collections_abc.Callable)
|
self.assertIsSubclass(C2, collections.abc.Callable)
|
||||||
self.assertIsSubclass(C1, collections_abc.Callable)
|
self.assertIsSubclass(C1, collections.abc.Callable)
|
||||||
self.assertIsInstance(T1(), tuple)
|
self.assertIsInstance(T1(), tuple)
|
||||||
self.assertIsSubclass(T2, tuple)
|
self.assertIsSubclass(T2, tuple)
|
||||||
self.assertIsSubclass(Tuple[int, ...], typing.Sequence)
|
with self.assertRaises(TypeError):
|
||||||
self.assertIsSubclass(Tuple[int, ...], typing.Iterable)
|
issubclass(Tuple[int, ...], typing.Sequence)
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
issubclass(Tuple[int, ...], typing.Iterable)
|
||||||
|
|
||||||
def test_fail_with_bare_union(self):
|
def test_fail_with_bare_union(self):
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
|
@ -1006,8 +1002,6 @@ class GenericTests(BaseTestCase):
|
||||||
Tuple[Generic[T]]
|
Tuple[Generic[T]]
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
List[typing._Protocol]
|
List[typing._Protocol]
|
||||||
with self.assertRaises(TypeError):
|
|
||||||
isinstance(1, Generic)
|
|
||||||
|
|
||||||
def test_type_erasure_special(self):
|
def test_type_erasure_special(self):
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
|
@ -1044,21 +1038,6 @@ class GenericTests(BaseTestCase):
|
||||||
self.assertNotEqual(repr(base), '')
|
self.assertNotEqual(repr(base), '')
|
||||||
self.assertEqual(base, base)
|
self.assertEqual(base, base)
|
||||||
|
|
||||||
def test_substitution_helper(self):
|
|
||||||
T = TypeVar('T')
|
|
||||||
KT = TypeVar('KT')
|
|
||||||
VT = TypeVar('VT')
|
|
||||||
class Map(Generic[KT, VT]):
|
|
||||||
def meth(self, k: KT, v: VT): ...
|
|
||||||
StrMap = Map[str, T]
|
|
||||||
obj = StrMap[int]()
|
|
||||||
|
|
||||||
new_args = typing._subs_tree(obj.__orig_class__)
|
|
||||||
new_annots = {k: typing._replace_arg(v, type(obj).__parameters__, new_args)
|
|
||||||
for k, v in obj.meth.__annotations__.items()}
|
|
||||||
|
|
||||||
self.assertEqual(new_annots, {'k': str, 'v': int})
|
|
||||||
|
|
||||||
def test_pickle(self):
|
def test_pickle(self):
|
||||||
global C # pickle wants to reference the class by name
|
global C # pickle wants to reference the class by name
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
|
@ -1078,12 +1057,20 @@ class GenericTests(BaseTestCase):
|
||||||
self.assertEqual(x.foo, 42)
|
self.assertEqual(x.foo, 42)
|
||||||
self.assertEqual(x.bar, 'abc')
|
self.assertEqual(x.bar, 'abc')
|
||||||
self.assertEqual(x.__dict__, {'foo': 42, 'bar': 'abc'})
|
self.assertEqual(x.__dict__, {'foo': 42, 'bar': 'abc'})
|
||||||
simples = [Any, Union, Tuple, Callable, ClassVar, List, typing.Iterable]
|
samples = [Any, Union, Tuple, Callable, ClassVar]
|
||||||
for s in simples:
|
for s in samples:
|
||||||
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
|
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
|
||||||
z = pickle.dumps(s, proto)
|
z = pickle.dumps(s, proto)
|
||||||
x = pickle.loads(z)
|
x = pickle.loads(z)
|
||||||
self.assertEqual(s, x)
|
self.assertEqual(s, x)
|
||||||
|
more_samples = [List, typing.Iterable, typing.Type]
|
||||||
|
for s in more_samples:
|
||||||
|
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
|
||||||
|
z = pickle.dumps(s, proto)
|
||||||
|
x = pickle.loads(z)
|
||||||
|
self.assertEqual(repr(s), repr(x)) # TODO: fix this
|
||||||
|
# see also comment in test_copy_and_deepcopy
|
||||||
|
# the issue is typing/#512
|
||||||
|
|
||||||
def test_copy_and_deepcopy(self):
|
def test_copy_and_deepcopy(self):
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
|
@ -1095,14 +1082,7 @@ class GenericTests(BaseTestCase):
|
||||||
Union['T', int], List['T'], typing.Mapping['T', int]]
|
Union['T', int], List['T'], typing.Mapping['T', int]]
|
||||||
for t in things + [Any]:
|
for t in things + [Any]:
|
||||||
self.assertEqual(t, copy(t))
|
self.assertEqual(t, copy(t))
|
||||||
self.assertEqual(t, deepcopy(t))
|
self.assertEqual(repr(t), repr(deepcopy(t))) # Use repr() because of TypeVars
|
||||||
if sys.version_info >= (3, 3):
|
|
||||||
# From copy module documentation:
|
|
||||||
# It does "copy" functions and classes (shallow and deeply), by returning
|
|
||||||
# the original object unchanged; this is compatible with the way these
|
|
||||||
# are treated by the pickle module.
|
|
||||||
self.assertTrue(t is copy(t))
|
|
||||||
self.assertTrue(t is deepcopy(t))
|
|
||||||
|
|
||||||
def test_copy_generic_instances(self):
|
def test_copy_generic_instances(self):
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
|
@ -1143,7 +1123,6 @@ class GenericTests(BaseTestCase):
|
||||||
|
|
||||||
c = C()
|
c = C()
|
||||||
c_int = C[int]()
|
c_int = C[int]()
|
||||||
self.assertEqual(C.__slots__, C[str].__slots__)
|
|
||||||
|
|
||||||
c.potato = 0
|
c.potato = 0
|
||||||
c_int.potato = 0
|
c_int.potato = 0
|
||||||
|
@ -1154,8 +1133,6 @@ class GenericTests(BaseTestCase):
|
||||||
|
|
||||||
def foo(x: C['C']): ...
|
def foo(x: C['C']): ...
|
||||||
self.assertEqual(get_type_hints(foo, globals(), locals())['x'], C[C])
|
self.assertEqual(get_type_hints(foo, globals(), locals())['x'], C[C])
|
||||||
self.assertEqual(get_type_hints(foo, globals(), locals())['x'].__slots__,
|
|
||||||
C.__slots__)
|
|
||||||
self.assertEqual(copy(C[int]), deepcopy(C[int]))
|
self.assertEqual(copy(C[int]), deepcopy(C[int]))
|
||||||
|
|
||||||
def test_parameterized_slots_dict(self):
|
def test_parameterized_slots_dict(self):
|
||||||
|
@ -1165,7 +1142,6 @@ class GenericTests(BaseTestCase):
|
||||||
|
|
||||||
d = D()
|
d = D()
|
||||||
d_int = D[int]()
|
d_int = D[int]()
|
||||||
self.assertEqual(D.__slots__, D[str].__slots__)
|
|
||||||
|
|
||||||
d.banana = 'yes'
|
d.banana = 'yes'
|
||||||
d_int.banana = 'yes'
|
d_int.banana = 'yes'
|
||||||
|
@ -1182,30 +1158,22 @@ class GenericTests(BaseTestCase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_repr_2(self):
|
def test_repr_2(self):
|
||||||
PY32 = sys.version_info[:2] < (3, 3)
|
|
||||||
|
|
||||||
class C(Generic[T]):
|
class C(Generic[T]):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.assertEqual(C.__module__, __name__)
|
self.assertEqual(C.__module__, __name__)
|
||||||
if not PY32:
|
self.assertEqual(C.__qualname__,
|
||||||
self.assertEqual(C.__qualname__,
|
'GenericTests.test_repr_2.<locals>.C')
|
||||||
'GenericTests.test_repr_2.<locals>.C')
|
|
||||||
self.assertEqual(repr(C).split('.')[-1], 'C')
|
|
||||||
X = C[int]
|
X = C[int]
|
||||||
self.assertEqual(X.__module__, __name__)
|
self.assertEqual(X.__module__, __name__)
|
||||||
if not PY32:
|
|
||||||
self.assertTrue(X.__qualname__.endswith('.<locals>.C'))
|
|
||||||
self.assertEqual(repr(X).split('.')[-1], 'C[int]')
|
self.assertEqual(repr(X).split('.')[-1], 'C[int]')
|
||||||
|
|
||||||
class Y(C[int]):
|
class Y(C[int]):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.assertEqual(Y.__module__, __name__)
|
self.assertEqual(Y.__module__, __name__)
|
||||||
if not PY32:
|
self.assertEqual(Y.__qualname__,
|
||||||
self.assertEqual(Y.__qualname__,
|
'GenericTests.test_repr_2.<locals>.Y')
|
||||||
'GenericTests.test_repr_2.<locals>.Y')
|
|
||||||
self.assertEqual(repr(Y).split('.')[-1], 'Y')
|
|
||||||
|
|
||||||
def test_eq_1(self):
|
def test_eq_1(self):
|
||||||
self.assertEqual(Generic, Generic)
|
self.assertEqual(Generic, Generic)
|
||||||
|
@ -1238,6 +1206,12 @@ class GenericTests(BaseTestCase):
|
||||||
|
|
||||||
self.assertEqual(C.__parameters__, (VT, T, KT))
|
self.assertEqual(C.__parameters__, (VT, T, KT))
|
||||||
|
|
||||||
|
def test_multiple_inheritance_special(self):
|
||||||
|
S = TypeVar('S')
|
||||||
|
class B(Generic[S]): ...
|
||||||
|
class C(List[int], B): ...
|
||||||
|
self.assertEqual(C.__mro__, (C, list, B, Generic, object))
|
||||||
|
|
||||||
def test_nested(self):
|
def test_nested(self):
|
||||||
|
|
||||||
G = Generic
|
G = Generic
|
||||||
|
@ -1408,22 +1382,22 @@ class ForwardRefTests(BaseTestCase):
|
||||||
self.assertEqual(right_hints['node'], Optional[Node[T]])
|
self.assertEqual(right_hints['node'], Optional[Node[T]])
|
||||||
|
|
||||||
def test_forwardref_instance_type_error(self):
|
def test_forwardref_instance_type_error(self):
|
||||||
fr = typing._ForwardRef('int')
|
fr = typing.ForwardRef('int')
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
isinstance(42, fr)
|
isinstance(42, fr)
|
||||||
|
|
||||||
def test_forwardref_subclass_type_error(self):
|
def test_forwardref_subclass_type_error(self):
|
||||||
fr = typing._ForwardRef('int')
|
fr = typing.ForwardRef('int')
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
issubclass(int, fr)
|
issubclass(int, fr)
|
||||||
|
|
||||||
def test_forward_equality(self):
|
def test_forward_equality(self):
|
||||||
fr = typing._ForwardRef('int')
|
fr = typing.ForwardRef('int')
|
||||||
self.assertEqual(fr, typing._ForwardRef('int'))
|
self.assertEqual(fr, typing.ForwardRef('int'))
|
||||||
self.assertNotEqual(List['int'], List[int])
|
self.assertNotEqual(List['int'], List[int])
|
||||||
|
|
||||||
def test_forward_repr(self):
|
def test_forward_repr(self):
|
||||||
self.assertEqual(repr(List['int']), "typing.List[_ForwardRef('int')]")
|
self.assertEqual(repr(List['int']), "typing.List[ForwardRef('int')]")
|
||||||
|
|
||||||
def test_union_forward(self):
|
def test_union_forward(self):
|
||||||
|
|
||||||
|
@ -1579,8 +1553,6 @@ class OverloadTests(BaseTestCase):
|
||||||
blah()
|
blah()
|
||||||
|
|
||||||
|
|
||||||
ASYNCIO = sys.version_info[:2] >= (3, 5)
|
|
||||||
|
|
||||||
ASYNCIO_TESTS = """
|
ASYNCIO_TESTS = """
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
|
@ -1618,17 +1590,15 @@ class ACM:
|
||||||
return None
|
return None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if ASYNCIO:
|
try:
|
||||||
try:
|
exec(ASYNCIO_TESTS)
|
||||||
exec(ASYNCIO_TESTS)
|
except ImportError:
|
||||||
except ImportError:
|
ASYNCIO = False # multithreading is not enabled
|
||||||
ASYNCIO = False
|
|
||||||
else:
|
else:
|
||||||
# fake names for the sake of static analysis
|
ASYNCIO = True
|
||||||
asyncio = None
|
|
||||||
AwaitableWrapper = AsyncIteratorWrapper = ACM = object
|
# Definitions needed for features introduced in Python 3.6
|
||||||
|
|
||||||
PY36_TESTS = """
|
|
||||||
from test import ann_module, ann_module2, ann_module3
|
from test import ann_module, ann_module2, ann_module3
|
||||||
from typing import AsyncContextManager
|
from typing import AsyncContextManager
|
||||||
|
|
||||||
|
@ -1681,15 +1651,6 @@ try:
|
||||||
g_with(ACM()).send(None)
|
g_with(ACM()).send(None)
|
||||||
except StopIteration as e:
|
except StopIteration as e:
|
||||||
assert e.args[0] == 42
|
assert e.args[0] == 42
|
||||||
"""
|
|
||||||
|
|
||||||
if PY36:
|
|
||||||
exec(PY36_TESTS)
|
|
||||||
else:
|
|
||||||
# fake names for the sake of static analysis
|
|
||||||
ann_module = ann_module2 = ann_module3 = None
|
|
||||||
A = B = CSub = G = CoolEmployee = CoolEmployeeWithDefault = object
|
|
||||||
XMeth = XRepr = NoneAndForward = object
|
|
||||||
|
|
||||||
gth = get_type_hints
|
gth = get_type_hints
|
||||||
|
|
||||||
|
@ -1704,14 +1665,12 @@ class GetTypeHintTests(BaseTestCase):
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
gth(None)
|
gth(None)
|
||||||
|
|
||||||
@skipUnless(PY36, 'Python 3.6 required')
|
|
||||||
def test_get_type_hints_modules(self):
|
def test_get_type_hints_modules(self):
|
||||||
ann_module_type_hints = {1: 2, 'f': Tuple[int, int], 'x': int, 'y': str}
|
ann_module_type_hints = {1: 2, 'f': Tuple[int, int], 'x': int, 'y': str}
|
||||||
self.assertEqual(gth(ann_module), ann_module_type_hints)
|
self.assertEqual(gth(ann_module), ann_module_type_hints)
|
||||||
self.assertEqual(gth(ann_module2), {})
|
self.assertEqual(gth(ann_module2), {})
|
||||||
self.assertEqual(gth(ann_module3), {})
|
self.assertEqual(gth(ann_module3), {})
|
||||||
|
|
||||||
@skipUnless(PY36, 'Python 3.6 required')
|
|
||||||
@expectedFailure
|
@expectedFailure
|
||||||
def test_get_type_hints_modules_forwardref(self):
|
def test_get_type_hints_modules_forwardref(self):
|
||||||
# FIXME: This currently exposes a bug in typing. Cached forward references
|
# FIXME: This currently exposes a bug in typing. Cached forward references
|
||||||
|
@ -1721,7 +1680,6 @@ class GetTypeHintTests(BaseTestCase):
|
||||||
'default_b': Optional[mod_generics_cache.B]}
|
'default_b': Optional[mod_generics_cache.B]}
|
||||||
self.assertEqual(gth(mod_generics_cache), mgc_hints)
|
self.assertEqual(gth(mod_generics_cache), mgc_hints)
|
||||||
|
|
||||||
@skipUnless(PY36, 'Python 3.6 required')
|
|
||||||
def test_get_type_hints_classes(self):
|
def test_get_type_hints_classes(self):
|
||||||
self.assertEqual(gth(ann_module.C), # gth will find the right globalns
|
self.assertEqual(gth(ann_module.C), # gth will find the right globalns
|
||||||
{'y': Optional[ann_module.C]})
|
{'y': Optional[ann_module.C]})
|
||||||
|
@ -1744,7 +1702,6 @@ class GetTypeHintTests(BaseTestCase):
|
||||||
'my_inner_a2': mod_generics_cache.B.A,
|
'my_inner_a2': mod_generics_cache.B.A,
|
||||||
'my_outer_a': mod_generics_cache.A})
|
'my_outer_a': mod_generics_cache.A})
|
||||||
|
|
||||||
@skipUnless(PY36, 'Python 3.6 required')
|
|
||||||
def test_respect_no_type_check(self):
|
def test_respect_no_type_check(self):
|
||||||
@no_type_check
|
@no_type_check
|
||||||
class NoTpCheck:
|
class NoTpCheck:
|
||||||
|
@ -1783,7 +1740,6 @@ class GetTypeHintTests(BaseTestCase):
|
||||||
b.__annotations__ = {'x': 'A'}
|
b.__annotations__ = {'x': 'A'}
|
||||||
self.assertEqual(gth(b, locals()), {'x': A})
|
self.assertEqual(gth(b, locals()), {'x': A})
|
||||||
|
|
||||||
@skipUnless(PY36, 'Python 3.6 required')
|
|
||||||
def test_get_type_hints_ClassVar(self):
|
def test_get_type_hints_ClassVar(self):
|
||||||
self.assertEqual(gth(ann_module2.CV, ann_module2.__dict__),
|
self.assertEqual(gth(ann_module2.CV, ann_module2.__dict__),
|
||||||
{'var': typing.ClassVar[ann_module2.CV]})
|
{'var': typing.ClassVar[ann_module2.CV]})
|
||||||
|
@ -2082,7 +2038,6 @@ class CollectionsAbcTests(BaseTestCase):
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
typing.Generator[int, int, int]()
|
typing.Generator[int, int, int]()
|
||||||
|
|
||||||
@skipUnless(PY36, 'Python 3.6 required')
|
|
||||||
def test_async_generator(self):
|
def test_async_generator(self):
|
||||||
ns = {}
|
ns = {}
|
||||||
exec("async def f():\n"
|
exec("async def f():\n"
|
||||||
|
@ -2090,7 +2045,6 @@ class CollectionsAbcTests(BaseTestCase):
|
||||||
g = ns['f']()
|
g = ns['f']()
|
||||||
self.assertIsSubclass(type(g), typing.AsyncGenerator)
|
self.assertIsSubclass(type(g), typing.AsyncGenerator)
|
||||||
|
|
||||||
@skipUnless(PY36, 'Python 3.6 required')
|
|
||||||
def test_no_async_generator_instantiation(self):
|
def test_no_async_generator_instantiation(self):
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
typing.AsyncGenerator()
|
typing.AsyncGenerator()
|
||||||
|
@ -2147,13 +2101,14 @@ class CollectionsAbcTests(BaseTestCase):
|
||||||
self.assertIsSubclass(MMC, typing.Mapping)
|
self.assertIsSubclass(MMC, typing.Mapping)
|
||||||
|
|
||||||
self.assertIsInstance(MMB[KT, VT](), typing.Mapping)
|
self.assertIsInstance(MMB[KT, VT](), typing.Mapping)
|
||||||
self.assertIsInstance(MMB[KT, VT](), collections_abc.Mapping)
|
self.assertIsInstance(MMB[KT, VT](), collections.abc.Mapping)
|
||||||
|
|
||||||
self.assertIsSubclass(MMA, collections_abc.Mapping)
|
self.assertIsSubclass(MMA, collections.abc.Mapping)
|
||||||
self.assertIsSubclass(MMB, collections_abc.Mapping)
|
self.assertIsSubclass(MMB, collections.abc.Mapping)
|
||||||
self.assertIsSubclass(MMC, collections_abc.Mapping)
|
self.assertIsSubclass(MMC, collections.abc.Mapping)
|
||||||
|
|
||||||
self.assertIsSubclass(MMB[str, str], typing.Mapping)
|
with self.assertRaises(TypeError):
|
||||||
|
issubclass(MMB[str, str], typing.Mapping)
|
||||||
self.assertIsSubclass(MMC, MMA)
|
self.assertIsSubclass(MMC, MMA)
|
||||||
|
|
||||||
class I(typing.Iterable): ...
|
class I(typing.Iterable): ...
|
||||||
|
@ -2163,12 +2118,10 @@ class CollectionsAbcTests(BaseTestCase):
|
||||||
def g(): yield 0
|
def g(): yield 0
|
||||||
self.assertIsSubclass(G, typing.Generator)
|
self.assertIsSubclass(G, typing.Generator)
|
||||||
self.assertIsSubclass(G, typing.Iterable)
|
self.assertIsSubclass(G, typing.Iterable)
|
||||||
if hasattr(collections_abc, 'Generator'):
|
self.assertIsSubclass(G, collections.abc.Generator)
|
||||||
self.assertIsSubclass(G, collections_abc.Generator)
|
self.assertIsSubclass(G, collections.abc.Iterable)
|
||||||
self.assertIsSubclass(G, collections_abc.Iterable)
|
|
||||||
self.assertNotIsSubclass(type(g), G)
|
self.assertNotIsSubclass(type(g), G)
|
||||||
|
|
||||||
@skipUnless(PY36, 'Python 3.6 required')
|
|
||||||
def test_subclassing_async_generator(self):
|
def test_subclassing_async_generator(self):
|
||||||
class G(typing.AsyncGenerator[int, int]):
|
class G(typing.AsyncGenerator[int, int]):
|
||||||
def asend(self, value):
|
def asend(self, value):
|
||||||
|
@ -2181,15 +2134,15 @@ class CollectionsAbcTests(BaseTestCase):
|
||||||
g = ns['g']
|
g = ns['g']
|
||||||
self.assertIsSubclass(G, typing.AsyncGenerator)
|
self.assertIsSubclass(G, typing.AsyncGenerator)
|
||||||
self.assertIsSubclass(G, typing.AsyncIterable)
|
self.assertIsSubclass(G, typing.AsyncIterable)
|
||||||
self.assertIsSubclass(G, collections_abc.AsyncGenerator)
|
self.assertIsSubclass(G, collections.abc.AsyncGenerator)
|
||||||
self.assertIsSubclass(G, collections_abc.AsyncIterable)
|
self.assertIsSubclass(G, collections.abc.AsyncIterable)
|
||||||
self.assertNotIsSubclass(type(g), G)
|
self.assertNotIsSubclass(type(g), G)
|
||||||
|
|
||||||
instance = G()
|
instance = G()
|
||||||
self.assertIsInstance(instance, typing.AsyncGenerator)
|
self.assertIsInstance(instance, typing.AsyncGenerator)
|
||||||
self.assertIsInstance(instance, typing.AsyncIterable)
|
self.assertIsInstance(instance, typing.AsyncIterable)
|
||||||
self.assertIsInstance(instance, collections_abc.AsyncGenerator)
|
self.assertIsInstance(instance, collections.abc.AsyncGenerator)
|
||||||
self.assertIsInstance(instance, collections_abc.AsyncIterable)
|
self.assertIsInstance(instance, collections.abc.AsyncIterable)
|
||||||
self.assertNotIsInstance(type(g), G)
|
self.assertNotIsInstance(type(g), G)
|
||||||
self.assertNotIsInstance(g, G)
|
self.assertNotIsInstance(g, G)
|
||||||
|
|
||||||
|
@ -2226,23 +2179,23 @@ class CollectionsAbcTests(BaseTestCase):
|
||||||
self.assertIsSubclass(D, B)
|
self.assertIsSubclass(D, B)
|
||||||
|
|
||||||
class M(): ...
|
class M(): ...
|
||||||
collections_abc.MutableMapping.register(M)
|
collections.abc.MutableMapping.register(M)
|
||||||
self.assertIsSubclass(M, typing.Mapping)
|
self.assertIsSubclass(M, typing.Mapping)
|
||||||
|
|
||||||
def test_collections_as_base(self):
|
def test_collections_as_base(self):
|
||||||
|
|
||||||
class M(collections_abc.Mapping): ...
|
class M(collections.abc.Mapping): ...
|
||||||
self.assertIsSubclass(M, typing.Mapping)
|
self.assertIsSubclass(M, typing.Mapping)
|
||||||
self.assertIsSubclass(M, typing.Iterable)
|
self.assertIsSubclass(M, typing.Iterable)
|
||||||
|
|
||||||
class S(collections_abc.MutableSequence): ...
|
class S(collections.abc.MutableSequence): ...
|
||||||
self.assertIsSubclass(S, typing.MutableSequence)
|
self.assertIsSubclass(S, typing.MutableSequence)
|
||||||
self.assertIsSubclass(S, typing.Iterable)
|
self.assertIsSubclass(S, typing.Iterable)
|
||||||
|
|
||||||
class I(collections_abc.Iterable): ...
|
class I(collections.abc.Iterable): ...
|
||||||
self.assertIsSubclass(I, typing.Iterable)
|
self.assertIsSubclass(I, typing.Iterable)
|
||||||
|
|
||||||
class A(collections_abc.Mapping, metaclass=abc.ABCMeta): ...
|
class A(collections.abc.Mapping, metaclass=abc.ABCMeta): ...
|
||||||
class B: ...
|
class B: ...
|
||||||
A.register(B)
|
A.register(B)
|
||||||
self.assertIsSubclass(B, typing.Mapping)
|
self.assertIsSubclass(B, typing.Mapping)
|
||||||
|
@ -2363,7 +2316,6 @@ class NamedTupleTests(BaseTestCase):
|
||||||
class NotYet(NamedTuple):
|
class NotYet(NamedTuple):
|
||||||
whatever = 0
|
whatever = 0
|
||||||
|
|
||||||
@skipUnless(PY36, 'Python 3.6 required')
|
|
||||||
def test_annotation_usage(self):
|
def test_annotation_usage(self):
|
||||||
tim = CoolEmployee('Tim', 9000)
|
tim = CoolEmployee('Tim', 9000)
|
||||||
self.assertIsInstance(tim, CoolEmployee)
|
self.assertIsInstance(tim, CoolEmployee)
|
||||||
|
@ -2376,7 +2328,6 @@ class NamedTupleTests(BaseTestCase):
|
||||||
collections.OrderedDict(name=str, cool=int))
|
collections.OrderedDict(name=str, cool=int))
|
||||||
self.assertIs(CoolEmployee._field_types, CoolEmployee.__annotations__)
|
self.assertIs(CoolEmployee._field_types, CoolEmployee.__annotations__)
|
||||||
|
|
||||||
@skipUnless(PY36, 'Python 3.6 required')
|
|
||||||
def test_annotation_usage_with_default(self):
|
def test_annotation_usage_with_default(self):
|
||||||
jelle = CoolEmployeeWithDefault('Jelle')
|
jelle = CoolEmployeeWithDefault('Jelle')
|
||||||
self.assertIsInstance(jelle, CoolEmployeeWithDefault)
|
self.assertIsInstance(jelle, CoolEmployeeWithDefault)
|
||||||
|
@ -2398,7 +2349,6 @@ class NonDefaultAfterDefault(NamedTuple):
|
||||||
y: int
|
y: int
|
||||||
""")
|
""")
|
||||||
|
|
||||||
@skipUnless(PY36, 'Python 3.6 required')
|
|
||||||
def test_annotation_usage_with_methods(self):
|
def test_annotation_usage_with_methods(self):
|
||||||
self.assertEqual(XMeth(1).double(), 2)
|
self.assertEqual(XMeth(1).double(), 2)
|
||||||
self.assertEqual(XMeth(42).x, XMeth(42)[0])
|
self.assertEqual(XMeth(42).x, XMeth(42)[0])
|
||||||
|
@ -2421,7 +2371,6 @@ class XMethBad2(NamedTuple):
|
||||||
return 'no chance for this as well'
|
return 'no chance for this as well'
|
||||||
""")
|
""")
|
||||||
|
|
||||||
@skipUnless(PY36, 'Python 3.6 required')
|
|
||||||
def test_namedtuple_keyword_usage(self):
|
def test_namedtuple_keyword_usage(self):
|
||||||
LocalEmployee = NamedTuple("LocalEmployee", name=str, age=int)
|
LocalEmployee = NamedTuple("LocalEmployee", name=str, age=int)
|
||||||
nick = LocalEmployee('Nick', 25)
|
nick = LocalEmployee('Nick', 25)
|
||||||
|
@ -2506,15 +2455,8 @@ class RETests(BaseTestCase):
|
||||||
self.assertNotEqual(Pattern[str], str)
|
self.assertNotEqual(Pattern[str], str)
|
||||||
|
|
||||||
def test_errors(self):
|
def test_errors(self):
|
||||||
with self.assertRaises(TypeError):
|
|
||||||
# Doesn't fit AnyStr.
|
|
||||||
Pattern[int]
|
|
||||||
with self.assertRaises(TypeError):
|
|
||||||
# Can't change type vars?
|
|
||||||
Match[T]
|
|
||||||
m = Match[Union[str, bytes]]
|
m = Match[Union[str, bytes]]
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
# Too complicated?
|
|
||||||
m[str]
|
m[str]
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
# We don't support isinstance().
|
# We don't support isinstance().
|
||||||
|
@ -2524,12 +2466,12 @@ class RETests(BaseTestCase):
|
||||||
issubclass(Pattern[bytes], Pattern[str])
|
issubclass(Pattern[bytes], Pattern[str])
|
||||||
|
|
||||||
def test_repr(self):
|
def test_repr(self):
|
||||||
self.assertEqual(repr(Pattern), 'Pattern[~AnyStr]')
|
self.assertEqual(repr(Pattern), 'typing.Pattern')
|
||||||
self.assertEqual(repr(Pattern[str]), 'Pattern[str]')
|
self.assertEqual(repr(Pattern[str]), 'typing.Pattern[str]')
|
||||||
self.assertEqual(repr(Pattern[bytes]), 'Pattern[bytes]')
|
self.assertEqual(repr(Pattern[bytes]), 'typing.Pattern[bytes]')
|
||||||
self.assertEqual(repr(Match), 'Match[~AnyStr]')
|
self.assertEqual(repr(Match), 'typing.Match')
|
||||||
self.assertEqual(repr(Match[str]), 'Match[str]')
|
self.assertEqual(repr(Match[str]), 'typing.Match[str]')
|
||||||
self.assertEqual(repr(Match[bytes]), 'Match[bytes]')
|
self.assertEqual(repr(Match[bytes]), 'typing.Match[bytes]')
|
||||||
|
|
||||||
def test_re_submodule(self):
|
def test_re_submodule(self):
|
||||||
from typing.re import Match, Pattern, __all__, __name__
|
from typing.re import Match, Pattern, __all__, __name__
|
||||||
|
@ -2545,7 +2487,7 @@ class RETests(BaseTestCase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.assertEqual(str(ex.exception),
|
self.assertEqual(str(ex.exception),
|
||||||
"Cannot subclass typing._TypeAlias")
|
"type 're.Match' is not an acceptable base type")
|
||||||
|
|
||||||
|
|
||||||
class AllTests(BaseTestCase):
|
class AllTests(BaseTestCase):
|
||||||
|
|
2163
Lib/typing.py
2163
Lib/typing.py
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue