Issue #24018: Add a collections.Generator abstract base class.

This commit is contained in:
Raymond Hettinger 2015-05-09 01:07:23 -04:00
parent dae2ef1cfa
commit bd60e8dece
4 changed files with 145 additions and 2 deletions

View file

@ -14,7 +14,7 @@ import sys
from collections import UserDict
from collections import ChainMap
from collections import deque
from collections.abc import Hashable, Iterable, Iterator
from collections.abc import Hashable, Iterable, Iterator, Generator
from collections.abc import Sized, Container, Callable
from collections.abc import Set, MutableSet
from collections.abc import Mapping, MutableMapping, KeysView, ItemsView
@ -522,6 +522,77 @@ class TestOneTrickPonyABCs(ABCTestCase):
return
self.assertNotIsInstance(NextOnly(), Iterator)
def test_Generator(self):
class NonGen1:
def __iter__(self): return self
def __next__(self): return None
def close(self): pass
def throw(self, typ, val=None, tb=None): pass
class NonGen2:
def __iter__(self): return self
def __next__(self): return None
def close(self): pass
def send(self, value): return value
class NonGen3:
def close(self): pass
def send(self, value): return value
def throw(self, typ, val=None, tb=None): pass
non_samples = [
None, 42, 3.14, 1j, b"", "", (), [], {}, set(),
iter(()), iter([]), NonGen1(), NonGen2(), NonGen3()]
for x in non_samples:
self.assertNotIsInstance(x, Generator)
self.assertFalse(issubclass(type(x), Generator), repr(type(x)))
class Gen:
def __iter__(self): return self
def __next__(self): return None
def close(self): pass
def send(self, value): return value
def throw(self, typ, val=None, tb=None): pass
class MinimalGen(Generator):
def send(self, value):
return value
def throw(self, typ, val=None, tb=None):
super().throw(typ, val, tb)
def gen():
yield 1
samples = [gen(), (lambda: (yield))(), Gen(), MinimalGen()]
for x in samples:
self.assertIsInstance(x, Iterator)
self.assertIsInstance(x, Generator)
self.assertTrue(issubclass(type(x), Generator), repr(type(x)))
self.validate_abstract_methods(Generator, 'send', 'throw')
# mixin tests
mgen = MinimalGen()
self.assertIs(mgen, iter(mgen))
self.assertIs(mgen.send(None), next(mgen))
self.assertEqual(2, mgen.send(2))
self.assertIsNone(mgen.close())
self.assertRaises(ValueError, mgen.throw, ValueError)
self.assertRaisesRegex(ValueError, "^huhu$",
mgen.throw, ValueError, ValueError("huhu"))
self.assertRaises(StopIteration, mgen.throw, StopIteration())
class FailOnClose(Generator):
def send(self, value): return value
def throw(self, *args): raise ValueError
self.assertRaises(ValueError, FailOnClose().close)
class IgnoreGeneratorExit(Generator):
def send(self, value): return value
def throw(self, *args): pass
self.assertRaises(RuntimeError, IgnoreGeneratorExit().close)
def test_Sized(self):
non_samples = [None, 42, 3.14, 1j,
(lambda: (yield))(),