]> granicus.if.org Git - python/commitdiff
Fix #27014 -- infinite recursion using typing.py.
authorGuido van Rossum <guido@python.org>
Wed, 18 May 2016 15:35:00 +0000 (08:35 -0700)
committerGuido van Rossum <guido@python.org>
Wed, 18 May 2016 15:35:00 +0000 (08:35 -0700)
Lib/test/test_typing.py
Lib/typing.py
Misc/NEWS

index 90bad775859fa1b8825839172cffedb2e3f21776..f9e54b2725fe11371ae49cc965bb235b228bff75 100644 (file)
@@ -1,4 +1,5 @@
 import contextlib
+import collections
 import pickle
 import re
 import sys
@@ -1218,13 +1219,17 @@ class CollectionsAbcTests(BaseTestCase):
         with self.assertRaises(TypeError):
             typing.List[int]()
 
-    def test_list_subclass_instantiation(self):
+    def test_list_subclass(self):
 
         class MyList(typing.List[int]):
             pass
 
         a = MyList()
         self.assertIsInstance(a, MyList)
+        self.assertIsInstance(a, typing.Sequence)
+
+        self.assertIsSubclass(MyList, list)
+        self.assertNotIsSubclass(list, MyList)
 
     def test_no_dict_instantiation(self):
         with self.assertRaises(TypeError):
@@ -1234,13 +1239,17 @@ class CollectionsAbcTests(BaseTestCase):
         with self.assertRaises(TypeError):
             typing.Dict[str, int]()
 
-    def test_dict_subclass_instantiation(self):
+    def test_dict_subclass(self):
 
         class MyDict(typing.Dict[str, int]):
             pass
 
         d = MyDict()
         self.assertIsInstance(d, MyDict)
+        self.assertIsInstance(d, typing.MutableMapping)
+
+        self.assertIsSubclass(MyDict, dict)
+        self.assertNotIsSubclass(dict, MyDict)
 
     def test_no_defaultdict_instantiation(self):
         with self.assertRaises(TypeError):
@@ -1250,7 +1259,7 @@ class CollectionsAbcTests(BaseTestCase):
         with self.assertRaises(TypeError):
             typing.DefaultDict[str, int]()
 
-    def test_defaultdict_subclass_instantiation(self):
+    def test_defaultdict_subclass(self):
 
         class MyDefDict(typing.DefaultDict[str, int]):
             pass
@@ -1258,6 +1267,9 @@ class CollectionsAbcTests(BaseTestCase):
         dd = MyDefDict()
         self.assertIsInstance(dd, MyDefDict)
 
+        self.assertIsSubclass(MyDefDict, collections.defaultdict)
+        self.assertNotIsSubclass(collections.defaultdict, MyDefDict)
+
     def test_no_set_instantiation(self):
         with self.assertRaises(TypeError):
             typing.Set()
@@ -1338,6 +1350,13 @@ class CollectionsAbcTests(BaseTestCase):
         self.assertEqual(len(MMB[str, str]()), 0)
         self.assertEqual(len(MMB[KT, VT]()), 0)
 
+        self.assertNotIsSubclass(dict, MMA)
+        self.assertNotIsSubclass(dict, MMB)
+
+        self.assertIsSubclass(MMA, typing.Mapping)
+        self.assertIsSubclass(MMB, typing.Mapping)
+        self.assertIsSubclass(MMC, typing.Mapping)
+
 
 class OtherABCTests(BaseTestCase):
 
index d2750111d4502e159108767206e1796675033392..841e778648a661c4d500a331edd314bb8c29546b 100644 (file)
@@ -894,8 +894,6 @@ def _next_in_mro(cls):
 class GenericMeta(TypingMeta, abc.ABCMeta):
     """Metaclass for generic types."""
 
-    __extra__ = None
-
     def __new__(cls, name, bases, namespace,
                 tvars=None, args=None, origin=None, extra=None):
         self = super().__new__(cls, name, bases, namespace, _root=True)
@@ -943,10 +941,7 @@ class GenericMeta(TypingMeta, abc.ABCMeta):
         self.__parameters__ = tvars
         self.__args__ = args
         self.__origin__ = origin
-        if extra is not None:
-            self.__extra__ = extra
-        # Else __extra__ is inherited, eventually from the
-        # (meta-)class default above.
+        self.__extra__ = extra
         # Speed hack (https://github.com/python/typing/issues/196).
         self.__next_in_mro__ = _next_in_mro(self)
         return self
@@ -1307,6 +1302,7 @@ class _ProtocolMeta(GenericMeta):
                             attr != '__next_in_mro__' and
                             attr != '__parameters__' and
                             attr != '__origin__' and
+                            attr != '__extra__' and
                             attr != '__module__'):
                         attrs.add(attr)
 
@@ -1470,7 +1466,7 @@ class ByteString(Sequence[int], extra=collections_abc.ByteString):
 ByteString.register(type(memoryview(b'')))
 
 
-class List(list, MutableSequence[T]):
+class List(list, MutableSequence[T], extra=list):
 
     def __new__(cls, *args, **kwds):
         if _geqv(cls, List):
@@ -1479,7 +1475,7 @@ class List(list, MutableSequence[T]):
         return list.__new__(cls, *args, **kwds)
 
 
-class Set(set, MutableSet[T]):
+class Set(set, MutableSet[T], extra=set):
 
     def __new__(cls, *args, **kwds):
         if _geqv(cls, Set):
@@ -1502,7 +1498,8 @@ class _FrozenSetMeta(GenericMeta):
         return super().__subclasscheck__(cls)
 
 
-class FrozenSet(frozenset, AbstractSet[T_co], metaclass=_FrozenSetMeta):
+class FrozenSet(frozenset, AbstractSet[T_co], metaclass=_FrozenSetMeta,
+                extra=frozenset):
     __slots__ = ()
 
     def __new__(cls, *args, **kwds):
@@ -1538,7 +1535,7 @@ if hasattr(contextlib, 'AbstractContextManager'):
     __all__.append('ContextManager')
 
 
-class Dict(dict, MutableMapping[KT, VT]):
+class Dict(dict, MutableMapping[KT, VT], extra=dict):
 
     def __new__(cls, *args, **kwds):
         if _geqv(cls, Dict):
@@ -1546,7 +1543,8 @@ class Dict(dict, MutableMapping[KT, VT]):
                             "use dict() instead")
         return dict.__new__(cls, *args, **kwds)
 
-class DefaultDict(collections.defaultdict, MutableMapping[KT, VT]):
+class DefaultDict(collections.defaultdict, MutableMapping[KT, VT],
+                  extra=collections.defaultdict):
 
     def __new__(cls, *args, **kwds):
         if _geqv(cls, DefaultDict):
index 97ddbb12f3dd2ae863da5a9ed4ea54067e80a6d9..8d91d7882a9afa33b7f07a747743f94d77f6b13b 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -123,6 +123,8 @@ Core and Builtins
 Library
 -------
 
+- Issue #27014: Fix infinite recursion using typing.py.  Thanks to Kalle Tuure!
+
 - Issue #14132: Fix urllib.request redirect handling when the target only has
   a query string.  Original fix by Ján Janech.