[Python-3000-checkins] r55849 - in python/branches/p3yk/Lib: collections.py test/test_collections.py

guido.van.rossum python-3000-checkins at python.org
Sun Jun 10 03:06:43 CEST 2007


Author: guido.van.rossum
Date: Sun Jun 10 03:06:38 2007
New Revision: 55849

Modified:
   python/branches/p3yk/Lib/collections.py
   python/branches/p3yk/Lib/test/test_collections.py
Log:
Make sure that the magic looking for __hash__ (etc.) doesn't apply to
real subclasses of Hashable.


Modified: python/branches/p3yk/Lib/collections.py
==============================================================================
--- python/branches/p3yk/Lib/collections.py	(original)
+++ python/branches/p3yk/Lib/collections.py	Sun Jun 10 03:06:38 2007
@@ -1,5 +1,7 @@
 __all__ = ['deque', 'defaultdict', 'NamedTuple',
            'Hashable', 'Iterable', 'Iterator', 'Sized', 'Container',
+           'Sequence', 'Set', 'Mapping',
+           'MutableSequence', 'MutableSet', 'MutableMapping',
            ]
 
 from _collections import deque, defaultdict
@@ -7,6 +9,7 @@
 import sys as _sys
 from abc import abstractmethod as _abstractmethod, ABCMeta as _ABCMeta
 
+
 def NamedTuple(typename, s):
     """Returns a new subclass of tuple with named fields.
 
@@ -57,6 +60,7 @@
     def __subclasshook__(self, subclass):
         return NotImplemented
 
+
 class Hashable(_OneTrickPony):
 
     @_abstractmethod
@@ -65,11 +69,12 @@
 
     @classmethod
     def __subclasshook__(cls, C):
-        for B in C.__mro__:
-            if "__hash__" in B.__dict__:
-                if B.__dict__["__hash__"]:
-                    return True
-                break
+        if cls is Hashable:
+            for B in C.__mro__:
+                if "__hash__" in B.__dict__:
+                    if B.__dict__["__hash__"]:
+                        return True
+                    break
         return NotImplemented
 
 
@@ -82,9 +87,10 @@
 
     @classmethod
     def __subclasshook__(cls, C):
-        if any("__iter__" in B.__dict__ or "__getitem__" in B.__dict__
-               for B in C.__mro__):
-            return True
+        if cls is Iterable:
+            if any("__iter__" in B.__dict__ or "__getitem__" in B.__dict__
+                   for B in C.__mro__):
+                return True
         return NotImplemented
 
 
@@ -99,8 +105,9 @@
 
     @classmethod
     def __subclasshook__(cls, C):
-        if any("__next__" in B.__dict__ for B in C.__mro__):
-            return True
+        if cls is Iterator:
+            if any("__next__" in B.__dict__ for B in C.__mro__):
+                return True
         return NotImplemented
 
 
@@ -112,8 +119,9 @@
 
     @classmethod
     def __subclasshook__(cls, C):
-        if any("__len__" in B.__dict__ for B in C.__mro__):
-            return True
+        if cls is Sized:
+            if any("__len__" in B.__dict__ for B in C.__mro__):
+                return True
         return NotImplemented
 
 
@@ -125,7 +133,10 @@
 
     @classmethod
     def __subclasshook__(cls, C):
-        return any("__contains__" in B.__dict__ for B in C.__mro__)
+        if cls is Container:
+            if any("__contains__" in B.__dict__ for B in C.__mro__):
+                return True
+        return NotImplemented
 
 
 if __name__ == '__main__':

Modified: python/branches/p3yk/Lib/test/test_collections.py
==============================================================================
--- python/branches/p3yk/Lib/test/test_collections.py	(original)
+++ python/branches/p3yk/Lib/test/test_collections.py	Sun Jun 10 03:06:38 2007
@@ -79,6 +79,7 @@
             def __hash__(self):
                 return super(H, self).__hash__()
         self.assertEqual(hash(H()), 0)
+        self.failIf(issubclass(int, H))
         # Check registration
         class C:
             __hash__ = None
@@ -87,16 +88,30 @@
         self.failUnless(issubclass(C, Hashable))
 
     def test_Iterable(self):
+        # Check some non-iterables
         non_samples = [None, 42, 3.14, 1j]
         for x in non_samples:
             self.failIf(isinstance(x, Iterable), repr(x))
             self.failIf(issubclass(type(x), Iterable), repr(type(x)))
+        # Check some iterables
         samples = [bytes(), str(), unicode(),
                    tuple(), list(), set(), frozenset(), dict(),
                    ]
         for x in samples:
             self.failUnless(isinstance(x, Iterable), repr(x))
             self.failUnless(issubclass(type(x), Iterable), repr(type(x)))
+        # Check direct subclassing
+        class I(Iterable):
+            def __iter__(self):
+                return super(I, self).__iter__()
+        self.assertEqual(list(I()), [])
+        self.failIf(issubclass(str, I))
+        # Check registration
+        class C:
+            pass
+        self.failIf(issubclass(C, Iterable))
+        Iterable.register(C)
+        self.failUnless(issubclass(C, Iterable))
 
     def test_Iterator(self):
         non_samples = [None, 42, 3.14, 1j, b"", "", u"", (), [], {}, set()]
@@ -142,5 +157,6 @@
     test_support.run_unittest(*test_classes)
     test_support.run_doctest(CollectionsModule, verbose)
 
+
 if __name__ == "__main__":
     test_main(verbose=True)


More information about the Python-3000-checkins mailing list