diff options
Diffstat (limited to 'Lib/test/test_generators.py')
-rw-r--r-- | Lib/test/test_generators.py | 135 |
1 files changed, 114 insertions, 21 deletions
diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index 604e12d..b92d5ce 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -3,7 +3,10 @@ import gc import pickle import sys import unittest +import warnings import weakref +import inspect +import types from test import support @@ -74,6 +77,42 @@ class FinalizationTest(unittest.TestCase): class GeneratorTest(unittest.TestCase): + def test_name(self): + def func(): + yield 1 + + # check generator names + gen = func() + self.assertEqual(gen.__name__, "func") + self.assertEqual(gen.__qualname__, + "GeneratorTest.test_name.<locals>.func") + + # modify generator names + gen.__name__ = "name" + gen.__qualname__ = "qualname" + self.assertEqual(gen.__name__, "name") + self.assertEqual(gen.__qualname__, "qualname") + + # generator names must be a string and cannot be deleted + self.assertRaises(TypeError, setattr, gen, '__name__', 123) + self.assertRaises(TypeError, setattr, gen, '__qualname__', 123) + self.assertRaises(TypeError, delattr, gen, '__name__') + self.assertRaises(TypeError, delattr, gen, '__qualname__') + + # modify names of the function creating the generator + func.__qualname__ = "func_qualname" + func.__name__ = "func_name" + gen = func() + self.assertEqual(gen.__name__, "func_name") + self.assertEqual(gen.__qualname__, "func_qualname") + + # unnamed generator + gen = (x for x in range(10)) + self.assertEqual(gen.__name__, + "<genexpr>") + self.assertEqual(gen.__qualname__, + "GeneratorTest.test_name.<locals>.<genexpr>") + def test_copy(self): def f(): yield 1 @@ -198,6 +237,79 @@ class ExceptionTest(unittest.TestCase): self.assertEqual(next(g), "done") self.assertEqual(sys.exc_info(), (None, None, None)) + def test_stopiteration_warning(self): + # See also PEP 479. + + def gen(): + raise StopIteration + yield + + with self.assertRaises(StopIteration), \ + self.assertWarnsRegex(PendingDeprecationWarning, "StopIteration"): + + next(gen()) + + with self.assertRaisesRegex(PendingDeprecationWarning, + "generator .* raised StopIteration"), \ + warnings.catch_warnings(): + + warnings.simplefilter('error') + next(gen()) + + + def test_tutorial_stopiteration(self): + # Raise StopIteration" stops the generator too: + + def f(): + yield 1 + raise StopIteration + yield 2 # never reached + + g = f() + self.assertEqual(next(g), 1) + + with self.assertWarnsRegex(PendingDeprecationWarning, "StopIteration"): + with self.assertRaises(StopIteration): + next(g) + + with self.assertRaises(StopIteration): + # This time StopIteration isn't raised from the generator's body, + # hence no warning. + next(g) + + +class YieldFromTests(unittest.TestCase): + def test_generator_gi_yieldfrom(self): + def a(): + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_RUNNING) + self.assertIsNone(gen_b.gi_yieldfrom) + yield + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_RUNNING) + self.assertIsNone(gen_b.gi_yieldfrom) + + def b(): + self.assertIsNone(gen_b.gi_yieldfrom) + yield from a() + self.assertIsNone(gen_b.gi_yieldfrom) + yield + self.assertIsNone(gen_b.gi_yieldfrom) + + gen_b = b() + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_CREATED) + self.assertIsNone(gen_b.gi_yieldfrom) + + gen_b.send(None) + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_SUSPENDED) + self.assertEqual(gen_b.gi_yieldfrom.gi_code.co_name, 'a') + + gen_b.send(None) + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_SUSPENDED) + self.assertIsNone(gen_b.gi_yieldfrom) + + [] = gen_b # Exhaust generator + self.assertEqual(inspect.getgeneratorstate(gen_b), inspect.GEN_CLOSED) + self.assertIsNone(gen_b.gi_yieldfrom) + tutorial_tests = """ Let's try a simple generator: @@ -244,26 +356,7 @@ Let's try a simple generator: File "<stdin>", line 1, in ? StopIteration -"raise StopIteration" stops the generator too: - - >>> def f(): - ... yield 1 - ... raise StopIteration - ... yield 2 # never reached - ... - >>> g = f() - >>> next(g) - 1 - >>> next(g) - Traceback (most recent call last): - File "<stdin>", line 1, in ? - StopIteration - >>> next(g) - Traceback (most recent call last): - File "<stdin>", line 1, in ? - StopIteration - -However, they are not exactly equivalent: +However, "return" and StopIteration are not exactly equivalent: >>> def g1(): ... try: @@ -583,7 +676,7 @@ From the Iterators list, about the types of these things. >>> type(i) <class 'generator'> >>> [s for s in dir(i) if not s.startswith('_')] -['close', 'gi_code', 'gi_frame', 'gi_running', 'send', 'throw'] +['close', 'gi_code', 'gi_frame', 'gi_running', 'gi_yieldfrom', 'send', 'throw'] >>> from test.support import HAVE_DOCSTRINGS >>> print(i.__next__.__doc__ if HAVE_DOCSTRINGS else 'Implement next(self).') Implement next(self). |