[Python-3000-checkins] r55838 - in python/branches/p3yk/Lib: collections.py test/test_collections.py
guido.van.rossum
python-3000-checkins at python.org
Sat Jun 9 02:38:59 CEST 2007
Author: guido.van.rossum
Date: Sat Jun 9 02:38:55 2007
New Revision: 55838
Modified:
python/branches/p3yk/Lib/collections.py
python/branches/p3yk/Lib/test/test_collections.py
Log:
Implement part of PEP 3119 -- One Trick Ponies.
Modified: python/branches/p3yk/Lib/collections.py
==============================================================================
--- python/branches/p3yk/Lib/collections.py (original)
+++ python/branches/p3yk/Lib/collections.py Sat Jun 9 02:38:55 2007
@@ -1,8 +1,11 @@
-__all__ = ['deque', 'defaultdict', 'NamedTuple']
+__all__ = ['deque', 'defaultdict', 'NamedTuple',
+ 'Hashable', 'Iterable', 'Iterator', 'Sized', 'Container',
+ ]
from _collections import deque, defaultdict
from operator import itemgetter as _itemgetter
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.
@@ -46,7 +49,79 @@
return result
+class _OneTrickPony(metaclass=_ABCMeta):
+ @classmethod
+ def __instancecheck__(cls, x):
+ return issubclass(x.__class__, cls)
+
+ @classmethod
+ def register(cls, C):
+ raise TypeError("class %s doesn't allow registration of subclasses" %
+ cls.__name__)
+
+
+class Hashable(_OneTrickPony):
+
+ @_abstractmethod
+ def __hash__(self):
+ return 0
+
+ @classmethod
+ def __subclasscheck__(cls, C):
+ for B in C.__mro__:
+ if "__hash__" in B.__dict__:
+ return B.__dict__["__hash__"] is not None
+ return False
+
+
+class Iterable(_OneTrickPony):
+
+ @_abstractmethod
+ def __iter__(self):
+ while False:
+ yield None
+
+ @classmethod
+ def __subclasscheck__(cls, C):
+ return any("__iter__" in B.__dict__ or "__getitem__" in B.__dict__
+ for B in C.__mro__)
+
+
+class Iterator(_OneTrickPony):
+
+ @_abstractmethod
+ def __next__(self):
+ raise StopIteration
+
+ def __iter__(self):
+ return self
+
+ @classmethod
+ def __subclasscheck__(cls, C):
+ return any("__next__" in B.__dict__ for B in C.__mro__)
+
+
+class Sized(_OneTrickPony):
+
+ @_abstractmethod
+ def __len__(self):
+ return 0
+
+ @classmethod
+ def __subclasscheck__(cls, C):
+ return any("__len__" in B.__dict__ for B in C.__mro__)
+
+
+class Container(_OneTrickPony):
+
+ @_abstractmethod
+ def __contains__(self, x):
+ return False
+
+ @classmethod
+ def __subclasscheck__(cls, C):
+ return any("__contains__" in B.__dict__ for B in C.__mro__)
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 Sat Jun 9 02:38:55 2007
@@ -1,6 +1,10 @@
+"""Unit tests for collections.py."""
+
import unittest
from test import test_support
from collections import NamedTuple
+from collections import Hashable, Iterable, Iterator, Sized, Container
+
class TestNamedTuple(unittest.TestCase):
@@ -51,9 +55,89 @@
self.assertRaises(AttributeError, eval, 'p.z', locals())
+class TestABCs(unittest.TestCase):
+
+ def test_Hashable(self):
+ # Check some non-hashables
+ non_samples = [bytes(), list(), set(), dict()]
+ for x in non_samples:
+ self.failIf(isinstance(x, Hashable), repr(x))
+ self.failIf(issubclass(type(x), Hashable), repr(type(x)))
+ # Check some hashables
+ samples = [None,
+ int(), float(), complex(),
+ str(), unicode(),
+ tuple(), frozenset(),
+ int, list, object, type,
+ ]
+ for x in samples:
+ self.failUnless(isinstance(x, Hashable), repr(x))
+ self.failUnless(issubclass(type(x), Hashable), repr(type(x)))
+ self.assertRaises(TypeError, Hashable)
+ # Check direct subclassing
+ class H(Hashable):
+ def __hash__(self):
+ return super(H, self).__hash__()
+ self.assertEqual(hash(H()), 0)
+ # Check registration is disabled
+ class C:
+ def __hash__(self):
+ return 0
+ self.assertRaises(TypeError, Hashable.register, C)
+
+ def test_Iterable(self):
+ 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)))
+ 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)))
+
+ def test_Iterator(self):
+ non_samples = [None, 42, 3.14, 1j, b"", "", u"", (), [], {}, set()]
+ for x in non_samples:
+ self.failIf(isinstance(x, Iterator), repr(x))
+ self.failIf(issubclass(type(x), Iterator), repr(type(x)))
+ samples = [iter(bytes()), iter(str()), iter(unicode()),
+ iter(tuple()), iter(list()), iter(dict()),
+ iter(set()), iter(frozenset()),
+ ]
+ for x in samples:
+ self.failUnless(isinstance(x, Iterator), repr(x))
+ self.failUnless(issubclass(type(x), Iterator), repr(type(x)))
+
+ def test_Sized(self):
+ non_samples = [None, 42, 3.14, 1j]
+ for x in non_samples:
+ self.failIf(isinstance(x, Sized), repr(x))
+ self.failIf(issubclass(type(x), Sized), repr(type(x)))
+ samples = [bytes(), str(), unicode(),
+ tuple(), list(), set(), frozenset(), dict(),
+ ]
+ for x in samples:
+ self.failUnless(isinstance(x, Sized), repr(x))
+ self.failUnless(issubclass(type(x), Sized), repr(type(x)))
+
+ def test_Container(self):
+ non_samples = [None, 42, 3.14, 1j]
+ for x in non_samples:
+ self.failIf(isinstance(x, Container), repr(x))
+ self.failIf(issubclass(type(x), Container), repr(type(x)))
+ samples = [bytes(), str(), unicode(),
+ tuple(), list(), set(), frozenset(), dict(),
+ ]
+ for x in samples:
+ self.failUnless(isinstance(x, Container), repr(x))
+ self.failUnless(issubclass(type(x), Container), repr(type(x)))
+
+
def test_main(verbose=None):
import collections as CollectionsModule
- test_classes = [TestNamedTuple]
+ test_classes = [TestNamedTuple, TestABCs]
test_support.run_unittest(*test_classes)
test_support.run_doctest(CollectionsModule, verbose)
More information about the Python-3000-checkins
mailing list