Issue 4920: Fixed next() vs __next__() issues in the ABCs

for Iterator and MutableSet.  Also added thorough test for
required abstractmethods.
This commit is contained in:
Raymond Hettinger 2009-01-28 23:02:26 +00:00
parent b1a98de25e
commit f779e6f51b
3 changed files with 68 additions and 4 deletions

View File

@ -60,7 +60,7 @@ Iterable.register(str)
class Iterator(Iterable):
@abstractmethod
def __next__(self):
def next(self):
raise StopIteration
def __iter__(self):
@ -267,7 +267,7 @@ class MutableSet(Set):
"""Return the popped value. Raise KeyError if empty."""
it = iter(self)
try:
value = it.__next__()
value = next(it)
except StopIteration:
raise KeyError
self.discard(value)

View File

@ -156,7 +156,24 @@ class TestNamedTuple(unittest.TestCase):
self.assertEqual(p, q)
self.assertEqual(p._fields, q._fields)
class TestOneTrickPonyABCs(unittest.TestCase):
class ABCTestCase(unittest.TestCase):
def validate_abstract_methods(self, abc, *names):
methodstubs = dict.fromkeys(names, lambda s, *args: 0)
# everything should work will all required methods are present
C = type('C', (abc,), methodstubs)
C()
# instantiation should fail if a required method is missing
for name in names:
stubs = methodstubs.copy()
del stubs[name]
C = type('C', (abc,), stubs)
self.assertRaises(TypeError, C, name)
class TestOneTrickPonyABCs(ABCTestCase):
def test_Hashable(self):
# Check some non-hashables
@ -182,6 +199,7 @@ class TestOneTrickPonyABCs(unittest.TestCase):
__eq__ = Hashable.__eq__ # Silence Py3k warning
self.assertEqual(hash(H()), 0)
self.failIf(issubclass(int, H))
self.validate_abstract_methods(Hashable, '__hash__')
def test_Iterable(self):
# Check some non-iterables
@ -205,6 +223,7 @@ class TestOneTrickPonyABCs(unittest.TestCase):
return super(I, self).__iter__()
self.assertEqual(list(I()), [])
self.failIf(issubclass(str, I))
self.validate_abstract_methods(Iterable, '__iter__')
def test_Iterator(self):
non_samples = [None, 42, 3.14, 1j, "".encode('ascii'), "", (), [],
@ -223,6 +242,7 @@ class TestOneTrickPonyABCs(unittest.TestCase):
for x in samples:
self.failUnless(isinstance(x, Iterator), repr(x))
self.failUnless(issubclass(type(x), Iterator), repr(type(x)))
self.validate_abstract_methods(Iterator, 'next')
def test_Sized(self):
non_samples = [None, 42, 3.14, 1j,
@ -239,6 +259,7 @@ class TestOneTrickPonyABCs(unittest.TestCase):
for x in samples:
self.failUnless(isinstance(x, Sized), repr(x))
self.failUnless(issubclass(type(x), Sized), repr(type(x)))
self.validate_abstract_methods(Sized, '__len__')
def test_Container(self):
non_samples = [None, 42, 3.14, 1j,
@ -255,6 +276,7 @@ class TestOneTrickPonyABCs(unittest.TestCase):
for x in samples:
self.failUnless(isinstance(x, Container), repr(x))
self.failUnless(issubclass(type(x), Container), repr(type(x)))
self.validate_abstract_methods(Container, '__contains__')
def test_Callable(self):
non_samples = [None, 42, 3.14, 1j,
@ -273,6 +295,7 @@ class TestOneTrickPonyABCs(unittest.TestCase):
for x in samples:
self.failUnless(isinstance(x, Callable), repr(x))
self.failUnless(issubclass(type(x), Callable), repr(type(x)))
self.validate_abstract_methods(Callable, '__call__')
def test_direct_subclassing(self):
for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
@ -291,7 +314,7 @@ class TestOneTrickPonyABCs(unittest.TestCase):
self.failUnless(issubclass(C, B))
class TestCollectionABCs(unittest.TestCase):
class TestCollectionABCs(ABCTestCase):
# XXX For now, we only test some virtual inheritance properties.
# We should also test the proper behavior of the collection ABCs
@ -301,6 +324,7 @@ class TestCollectionABCs(unittest.TestCase):
for sample in [set, frozenset]:
self.failUnless(isinstance(sample(), Set))
self.failUnless(issubclass(sample, Set))
self.validate_abstract_methods(Set, '__contains__', '__iter__', '__len__')
def test_hash_Set(self):
class OneTwoThreeSet(Set):
@ -322,22 +346,57 @@ class TestCollectionABCs(unittest.TestCase):
self.failUnless(issubclass(set, MutableSet))
self.failIf(isinstance(frozenset(), MutableSet))
self.failIf(issubclass(frozenset, MutableSet))
self.validate_abstract_methods(MutableSet, '__contains__', '__iter__', '__len__',
'add', 'discard')
def test_issue_4920(self):
# MutableSet.pop() method did not work
class MySet(collections.MutableSet):
__slots__=['__s']
def __init__(self,items=None):
if items is None:
items=[]
self.__s=set(items)
def __contains__(self,v):
return v in self.__s
def __iter__(self):
return iter(self.__s)
def __len__(self):
return len(self.__s)
def add(self,v):
result=v not in self.__s
self.__s.add(v)
return result
def discard(self,v):
result=v in self.__s
self.__s.discard(v)
return result
def __repr__(self):
return "MySet(%s)" % repr(list(self))
s = MySet([5,43,2,1])
self.assertEqual(s.pop(), 1)
def test_Mapping(self):
for sample in [dict]:
self.failUnless(isinstance(sample(), Mapping))
self.failUnless(issubclass(sample, Mapping))
self.validate_abstract_methods(Mapping, '__contains__', '__iter__', '__len__',
'__getitem__')
def test_MutableMapping(self):
for sample in [dict]:
self.failUnless(isinstance(sample(), MutableMapping))
self.failUnless(issubclass(sample, MutableMapping))
self.validate_abstract_methods(MutableMapping, '__contains__', '__iter__', '__len__',
'__getitem__', '__setitem__', '__delitem__')
def test_Sequence(self):
for sample in [tuple, list, str]:
self.failUnless(isinstance(sample(), Sequence))
self.failUnless(issubclass(sample, Sequence))
self.failUnless(issubclass(basestring, Sequence))
self.validate_abstract_methods(Sequence, '__contains__', '__iter__', '__len__',
'__getitem__')
def test_MutableSequence(self):
for sample in [tuple, str]:
@ -347,6 +406,8 @@ class TestCollectionABCs(unittest.TestCase):
self.failUnless(isinstance(sample(), MutableSequence))
self.failUnless(issubclass(sample, MutableSequence))
self.failIf(issubclass(basestring, MutableSequence))
self.validate_abstract_methods(MutableSequence, '__contains__', '__iter__',
'__len__', '__getitem__', '__setitem__', '__delitem__', 'insert')
class TestCounter(unittest.TestCase):

View File

@ -145,6 +145,9 @@ Core and Builtins
Library
-------
- Issue 4920: Fixed .next() vs .__next__() issues in the ABCs for
Iterator and MutableSet.
- Added the ttk module. See issue #2983: Ttk support for Tkinter.
- Issue 5021: doctest.testfile() did not create __name__ and