Skip to content

Commit 7fe091d

Browse files
committed
More updates from upstream typing.py (3.5->3.6)
2 parents 0a6ef79 + b47c9d2 commit 7fe091d

File tree

2 files changed

+108
-64
lines changed

2 files changed

+108
-64
lines changed

Lib/test/test_typing.py

+38-29
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,13 @@ def test_subclass_error(self):
202202
def test_union_any(self):
203203
u = Union[Any]
204204
self.assertEqual(u, Any)
205-
u = Union[int, Any]
206-
self.assertEqual(u, Any)
207-
u = Union[Any, int]
208-
self.assertEqual(u, Any)
205+
u1 = Union[int, Any]
206+
u2 = Union[Any, int]
207+
u3 = Union[Any, object]
208+
self.assertEqual(u1, u2)
209+
self.assertNotEqual(u1, Any)
210+
self.assertNotEqual(u2, Any)
211+
self.assertNotEqual(u3, Any)
209212

210213
def test_union_object(self):
211214
u = Union[object]
@@ -215,12 +218,6 @@ def test_union_object(self):
215218
u = Union[object, int]
216219
self.assertEqual(u, object)
217220

218-
def test_union_any_object(self):
219-
u = Union[object, Any]
220-
self.assertEqual(u, Any)
221-
u = Union[Any, object]
222-
self.assertEqual(u, Any)
223-
224221
def test_unordered(self):
225222
u1 = Union[int, float]
226223
u2 = Union[float, int]
@@ -600,8 +597,8 @@ class MyMapping(MutableMapping[str, str]): pass
600597
self.assertNotIsInstance({}, MyMapping)
601598
self.assertNotIsSubclass(dict, MyMapping)
602599

603-
def test_multiple_abc_bases(self):
604-
class MM1(MutableMapping[str, str], collections_abc.MutableMapping):
600+
def test_abc_bases(self):
601+
class MM(MutableMapping[str, str]):
605602
def __getitem__(self, k):
606603
return None
607604
def __setitem__(self, k, v):
@@ -612,24 +609,20 @@ def __iter__(self):
612609
return iter(())
613610
def __len__(self):
614611
return 0
615-
class MM2(collections_abc.MutableMapping, MutableMapping[str, str]):
616-
def __getitem__(self, k):
617-
return None
618-
def __setitem__(self, k, v):
619-
pass
620-
def __delitem__(self, k):
612+
# this should just work
613+
MM().update()
614+
self.assertIsInstance(MM(), collections_abc.MutableMapping)
615+
self.assertIsInstance(MM(), MutableMapping)
616+
self.assertNotIsInstance(MM(), List)
617+
self.assertNotIsInstance({}, MM)
618+
619+
def test_multiple_bases(self):
620+
class MM1(MutableMapping[str, str], collections_abc.MutableMapping):
621+
pass
622+
with self.assertRaises(TypeError):
623+
# consistent MRO not possible
624+
class MM2(collections_abc.MutableMapping, MutableMapping[str, str]):
621625
pass
622-
def __iter__(self):
623-
return iter(())
624-
def __len__(self):
625-
return 0
626-
# these two should just work
627-
MM1().update()
628-
MM2().update()
629-
self.assertIsInstance(MM1(), collections_abc.MutableMapping)
630-
self.assertIsInstance(MM1(), MutableMapping)
631-
self.assertIsInstance(MM2(), collections_abc.MutableMapping)
632-
self.assertIsInstance(MM2(), MutableMapping)
633626

634627
def test_pickle(self):
635628
global C # pickle wants to reference the class by name
@@ -1380,12 +1373,28 @@ class MMA(typing.MutableMapping):
13801373
MMA()
13811374

13821375
class MMC(MMA):
1376+
def __getitem__(self, k):
1377+
return None
1378+
def __setitem__(self, k, v):
1379+
pass
1380+
def __delitem__(self, k):
1381+
pass
1382+
def __iter__(self):
1383+
return iter(())
13831384
def __len__(self):
13841385
return 0
13851386

13861387
self.assertEqual(len(MMC()), 0)
13871388

13881389
class MMB(typing.MutableMapping[KT, VT]):
1390+
def __getitem__(self, k):
1391+
return None
1392+
def __setitem__(self, k, v):
1393+
pass
1394+
def __delitem__(self, k):
1395+
pass
1396+
def __iter__(self):
1397+
return iter(())
13891398
def __len__(self):
13901399
return 0
13911400

Lib/typing.py

+70-35
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,6 @@ class _TypingBase(metaclass=TypingMeta, _root=True):
143143

144144
__slots__ = ()
145145

146-
147146
def __init__(self, *args, **kwds):
148147
pass
149148

@@ -158,7 +157,7 @@ def __new__(cls, *args, **kwds):
158157
isinstance(args[1], tuple)):
159158
# Close enough.
160159
raise TypeError("Cannot subclass %r" % cls)
161-
return object.__new__(cls)
160+
return super().__new__(cls)
162161

163162
# Things that are not classes also need these.
164163
def _eval_type(self, globalns, localns):
@@ -177,7 +176,11 @@ def __call__(self, *args, **kwds):
177176

178177

179178
class _FinalTypingBase(_TypingBase, _root=True):
180-
"""Mix-in class to prevent instantiation."""
179+
"""Mix-in class to prevent instantiation.
180+
181+
Prevents instantiation unless _root=True is given in class call.
182+
It is used to create pseudo-singleton instances Any, Union, Tuple, etc.
183+
"""
181184

182185
__slots__ = ()
183186

@@ -273,7 +276,7 @@ def __init__(self, name, type_var, impl_type, type_checker):
273276
assert isinstance(name, str), repr(name)
274277
assert isinstance(impl_type, type), repr(impl_type)
275278
assert not isinstance(impl_type, TypingMeta), repr(impl_type)
276-
assert isinstance(type_var, (type, _TypingBase))
279+
assert isinstance(type_var, (type, _TypingBase)), repr(type_var)
277280
self.name = name
278281
self.type_var = type_var
279282
self.impl_type = impl_type
@@ -375,9 +378,13 @@ def _type_repr(obj):
375378
class _Any(_FinalTypingBase, _root=True):
376379
"""Special type indicating an unconstrained type.
377380
378-
- Any object is an instance of Any.
379-
- Any class is a subclass of Any.
380-
- As a special case, Any and object are subclasses of each other.
381+
- Any is compatible with every type.
382+
- Any assumed to have all methods.
383+
- All values assumed to be instances of Any.
384+
385+
Note that all the above statements are true from the point of view of
386+
static type checkers. At runtime, Any should not be used with instance
387+
or class checks.
381388
"""
382389

383390
__slots__ = ()
@@ -502,7 +509,7 @@ def inner(*args, **kwds):
502509
try:
503510
return cached(*args, **kwds)
504511
except TypeError:
505-
pass # Do not duplicate real errors.
512+
pass # All real errors (not unhashable args) are raised below.
506513
return func(*args, **kwds)
507514
return inner
508515

@@ -542,16 +549,10 @@ class Manager(Employee): pass
542549
Union[Manager, int, Employee] == Union[int, Employee]
543550
Union[Employee, Manager] == Employee
544551
545-
- Corollary: if Any is present it is the sole survivor, e.g.::
546-
547-
Union[int, Any] == Any
548-
549552
- Similar for object::
550553
551554
Union[int, object] == object
552555
553-
- To cut a tie: Union[object, Any] == Union[Any, object] == Any.
554-
555556
- You cannot subclass or instantiate a union.
556557
557558
- You cannot write Union[X][Y] (what would it mean?).
@@ -589,14 +590,11 @@ def __new__(cls, parameters=None, *args, _root=False):
589590
assert not all_params, all_params
590591
# Weed out subclasses.
591592
# E.g. Union[int, Employee, Manager] == Union[int, Employee].
592-
# If Any or object is present it will be the sole survivor.
593-
# If both Any and object are present, Any wins.
594-
# Never discard type variables, except against Any.
593+
# If object is present it will be sole survivor among proper classes.
594+
# Never discard type variables.
595595
# (In particular, Union[str, AnyStr] != AnyStr.)
596596
all_params = set(params)
597597
for t1 in params:
598-
if t1 is Any:
599-
return Any
600598
if not isinstance(t1, type):
601599
continue
602600
if any(isinstance(t2, type) and issubclass(t1, t2)
@@ -662,7 +660,7 @@ def __subclasscheck__(self, cls):
662660
class _Optional(_FinalTypingBase, _root=True):
663661
"""Optional type.
664662
665-
Optional[X] is equivalent to Union[X, type(None)].
663+
Optional[X] is equivalent to Union[X, None].
666664
"""
667665

668666
__slots__ = ()
@@ -894,11 +892,55 @@ def _next_in_mro(cls):
894892
return next_in_mro
895893

896894

895+
def _valid_for_check(cls):
896+
if cls is Generic:
897+
raise TypeError("Class %r cannot be used with class "
898+
"or instance checks" % cls)
899+
if (cls.__origin__ is not None and
900+
sys._getframe(3).f_globals['__name__'] not in ['abc', 'functools']):
901+
raise TypeError("Parameterized generics cannot be used with class "
902+
"or instance checks")
903+
904+
905+
def _make_subclasshook(cls):
906+
"""Construct a __subclasshook__ callable that incorporates
907+
the associated __extra__ class in subclass checks performed
908+
against cls.
909+
"""
910+
if isinstance(cls.__extra__, abc.ABCMeta):
911+
# The logic mirrors that of ABCMeta.__subclasscheck__.
912+
# Registered classes need not be checked here because
913+
# cls and its extra share the same _abc_registry.
914+
def __extrahook__(subclass):
915+
_valid_for_check(cls)
916+
res = cls.__extra__.__subclasshook__(subclass)
917+
if res is not NotImplemented:
918+
return res
919+
if cls.__extra__ in subclass.__mro__:
920+
return True
921+
for scls in cls.__extra__.__subclasses__():
922+
if isinstance(scls, GenericMeta):
923+
continue
924+
if issubclass(subclass, scls):
925+
return True
926+
return NotImplemented
927+
else:
928+
# For non-ABC extras we'll just call issubclass().
929+
def __extrahook__(subclass):
930+
_valid_for_check(cls)
931+
if cls.__extra__ and issubclass(subclass, cls.__extra__):
932+
return True
933+
return NotImplemented
934+
return __extrahook__
935+
936+
897937
class GenericMeta(TypingMeta, abc.ABCMeta):
898938
"""Metaclass for generic types."""
899939

900940
def __new__(cls, name, bases, namespace,
901941
tvars=None, args=None, origin=None, extra=None):
942+
if extra is not None and type(extra) is abc.ABCMeta and extra not in bases:
943+
bases = (extra,) + bases
902944
self = super().__new__(cls, name, bases, namespace, _root=True)
903945

904946
if tvars is not None:
@@ -947,6 +989,13 @@ def __new__(cls, name, bases, namespace,
947989
self.__extra__ = extra
948990
# Speed hack (https://github.com/python/typing/issues/196).
949991
self.__next_in_mro__ = _next_in_mro(self)
992+
993+
# This allows unparameterized generic collections to be used
994+
# with issubclass() and isinstance() in the same way as their
995+
# collections.abc counterparts (e.g., isinstance([], Iterable)).
996+
self.__subclasshook__ = _make_subclasshook(self)
997+
if isinstance(extra, abc.ABCMeta):
998+
self._abc_registry = extra._abc_registry
950999
return self
9511000

9521001
def _get_type_vars(self, tvars):
@@ -1032,21 +1081,7 @@ def __instancecheck__(self, instance):
10321081
# latter, we must extend __instancecheck__ too. For simplicity
10331082
# we just skip the cache check -- instance checks for generic
10341083
# classes are supposed to be rare anyways.
1035-
return self.__subclasscheck__(instance.__class__)
1036-
1037-
def __subclasscheck__(self, cls):
1038-
if self is Generic:
1039-
raise TypeError("Class %r cannot be used with class "
1040-
"or instance checks" % self)
1041-
if (self.__origin__ is not None and
1042-
sys._getframe(1).f_globals['__name__'] != 'abc'):
1043-
raise TypeError("Parameterized generics cannot be used with class "
1044-
"or instance checks")
1045-
if super().__subclasscheck__(cls):
1046-
return True
1047-
if self.__extra__ is not None:
1048-
return issubclass(cls, self.__extra__)
1049-
return False
1084+
return issubclass(instance.__class__, self)
10501085

10511086

10521087
# Prevent checks for Generic to crash when defining Generic.

0 commit comments

Comments
 (0)