diff options
Diffstat (limited to 'Lib/test/test_generators.py')
-rw-r--r-- | Lib/test/test_generators.py | 369 |
1 files changed, 196 insertions, 173 deletions
diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py index 19bfe074c4e..5f47b3eae03 100644 --- a/Lib/test/test_generators.py +++ b/Lib/test/test_generators.py @@ -6,18 +6,18 @@ Let's try a simple generator: ... yield 2 >>> for i in f(): - ... print i + ... print(i) 1 2 >>> g = f() - >>> g.next() + >>> next(g) 1 - >>> g.next() + >>> next(g) 2 "Falling off the end" stops the generator: - >>> g.next() + >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 2, in g @@ -31,14 +31,14 @@ Let's try a simple generator: ... yield 2 # never reached ... >>> g = f() - >>> g.next() + >>> next(g) 1 - >>> g.next() + >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 3, in f StopIteration - >>> g.next() # once stopped, can't be resumed + >>> next(g) # once stopped, can't be resumed Traceback (most recent call last): File "<stdin>", line 1, in ? StopIteration @@ -51,13 +51,13 @@ Let's try a simple generator: ... yield 2 # never reached ... >>> g = f() - >>> g.next() + >>> next(g) 1 - >>> g.next() + >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in ? StopIteration - >>> g.next() + >>> next(g) Traceback (most recent call last): File "<stdin>", line 1, in ? StopIteration @@ -78,7 +78,7 @@ However, they are not exactly equivalent: ... raise StopIteration ... except: ... yield 42 - >>> print list(g2()) + >>> print(list(g2())) [42] This may be surprising at first: @@ -105,13 +105,13 @@ Generators always return to the most recent caller: >>> def creator(): ... r = yrange(5) - ... print "creator", r.next() + ... print("creator", next(r)) ... return r ... >>> def caller(): ... r = creator() ... for i in r: - ... print "caller", i + ... print("caller", i) ... >>> caller() creator 0 @@ -141,10 +141,10 @@ Specification: Yield running: >>> def g(): - ... i = me.next() + ... i = next(me) ... yield i >>> me = g() - >>> me.next() + >>> next(me) Traceback (most recent call last): ... File "<string>", line 2, in g @@ -161,7 +161,7 @@ Specification: Return ... return ... except: ... yield 1 - >>> print list(f1()) + >>> print(list(f1())) [] because, as in any function, return simply exits, but @@ -171,7 +171,7 @@ Specification: Return ... raise StopIteration ... except: ... yield 42 - >>> print list(f2()) + >>> print(list(f2())) [42] because StopIteration is captured by a bare "except", as is any @@ -185,13 +185,13 @@ Specification: Generators and Exception Propagation ... yield f() # the zero division exception propagates ... yield 42 # and we'll never get here >>> k = g() - >>> k.next() + >>> next(k) Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 2, in g File "<stdin>", line 2, in f ZeroDivisionError: integer division or modulo by zero - >>> k.next() # and the generator cannot be resumed + >>> next(k) # and the generator cannot be resumed Traceback (most recent call last): File "<stdin>", line 1, in ? StopIteration @@ -221,7 +221,7 @@ Specification: Try/Except/Finally ... finally: ... yield 10 ... yield 11 - >>> print list(f()) + >>> print(list(f())) [1, 2, 4, 5, 8, 9, 10, 11] >>> @@ -270,8 +270,8 @@ Guido's binary tree example. >>> t = tree("ABCDEFGHIJKLMNOPQRSTUVWXYZ") >>> # Print the nodes of the tree in in-order. >>> for x in t: - ... print x, - A B C D E F G H I J K L M N O P Q R S T U V W X Y Z + ... print(' '+x, end='') + A B C D E F G H I J K L M N O P Q R S T U V W X Y Z >>> # A non-recursive generator. >>> def inorder(node): @@ -291,8 +291,8 @@ Guido's binary tree example. >>> # Exercise the non-recursive generator. >>> for x in t: - ... print x, - A B C D E F G H I J K L M N O P Q R S T U V W X Y Z + ... print(' '+x, end='') + A B C D E F G H I J K L M N O P Q R S T U V W X Y Z """ @@ -343,11 +343,11 @@ Next one was posted to c.l.py. ... for c in gcomb(rest, k): ... yield c ->>> seq = range(1, 5) +>>> seq = list(range(1, 5)) >>> for k in range(len(seq) + 2): -... print "%d-combs of %s:" % (k, seq) +... print("%d-combs of %s:" % (k, seq)) ... for c in gcomb(seq, k): -... print " ", c +... print(" ", c) 0-combs of [1, 2, 3, 4]: [] 1-combs of [1, 2, 3, 4]: @@ -377,14 +377,14 @@ From the Iterators list, about the types of these things. ... yield 1 ... >>> type(g) -<type 'function'> +<class 'function'> >>> i = g() >>> type(i) -<type 'generator'> +<class 'generator'> >>> [s for s in dir(i) if not s.startswith('_')] -['close', 'gi_code', 'gi_frame', 'gi_running', 'next', 'send', 'throw'] ->>> print i.next.__doc__ -x.next() -> the next value, or raise StopIteration +['close', 'gi_code', 'gi_frame', 'gi_running', 'send', 'throw'] +>>> print(i.__next__.__doc__) +x.__next__() <==> next(x) >>> iter(i) is i True >>> import types @@ -396,17 +396,17 @@ And more, added later. >>> i.gi_running 0 >>> type(i.gi_frame) -<type 'frame'> +<class 'frame'> >>> i.gi_running = 42 Traceback (most recent call last): ... -TypeError: readonly attribute +AttributeError: readonly attribute >>> def g(): ... yield me.gi_running >>> me = g() >>> me.gi_running 0 ->>> me.next() +>>> next(me) 1 >>> me.gi_running 0 @@ -429,7 +429,7 @@ Subject: Re: PEP 255: Simple Generators ... yield x ... ... def find(self): -... return self.generator.next() +... return next(self.generator) ... ... def union(self, parent): ... if self.parent: @@ -444,44 +444,44 @@ Subject: Re: PEP 255: Simple Generators >>> roots = sets[:] >>> import random ->>> gen = random.WichmannHill(42) +>>> gen = random.Random(42) >>> while 1: ... for s in sets: -... print "%s->%s" % (s, s.find()), -... print +... print(" %s->%s" % (s, s.find()), end='') +... print() ... if len(roots) > 1: ... s1 = gen.choice(roots) ... roots.remove(s1) ... s2 = gen.choice(roots) ... s1.union(s2) -... print "merged", s1, "into", s2 +... print("merged", s1, "into", s2) ... else: ... break -A->A B->B C->C D->D E->E F->F G->G H->H I->I J->J K->K L->L M->M -merged D into G -A->A B->B C->C D->G E->E F->F G->G H->H I->I J->J K->K L->L M->M -merged C into F -A->A B->B C->F D->G E->E F->F G->G H->H I->I J->J K->K L->L M->M -merged L into A -A->A B->B C->F D->G E->E F->F G->G H->H I->I J->J K->K L->A M->M -merged H into E -A->A B->B C->F D->G E->E F->F G->G H->E I->I J->J K->K L->A M->M -merged B into E -A->A B->E C->F D->G E->E F->F G->G H->E I->I J->J K->K L->A M->M -merged J into G -A->A B->E C->F D->G E->E F->F G->G H->E I->I J->G K->K L->A M->M -merged E into G -A->A B->G C->F D->G E->G F->F G->G H->G I->I J->G K->K L->A M->M -merged M into G -A->A B->G C->F D->G E->G F->F G->G H->G I->I J->G K->K L->A M->G -merged I into K -A->A B->G C->F D->G E->G F->F G->G H->G I->K J->G K->K L->A M->G -merged K into A -A->A B->G C->F D->G E->G F->F G->G H->G I->A J->G K->A L->A M->G -merged F into A -A->A B->G C->A D->G E->G F->A G->G H->G I->A J->G K->A L->A M->G -merged A into G -A->G B->G C->G D->G E->G F->G G->G H->G I->G J->G K->G L->G M->G + A->A B->B C->C D->D E->E F->F G->G H->H I->I J->J K->K L->L M->M +merged K into B + A->A B->B C->C D->D E->E F->F G->G H->H I->I J->J K->B L->L M->M +merged A into F + A->F B->B C->C D->D E->E F->F G->G H->H I->I J->J K->B L->L M->M +merged E into F + A->F B->B C->C D->D E->F F->F G->G H->H I->I J->J K->B L->L M->M +merged D into C + A->F B->B C->C D->C E->F F->F G->G H->H I->I J->J K->B L->L M->M +merged M into C + A->F B->B C->C D->C E->F F->F G->G H->H I->I J->J K->B L->L M->C +merged J into B + A->F B->B C->C D->C E->F F->F G->G H->H I->I J->B K->B L->L M->C +merged B into C + A->F B->C C->C D->C E->F F->F G->G H->H I->I J->C K->C L->L M->C +merged F into G + A->G B->C C->C D->C E->G F->G G->G H->H I->I J->C K->C L->L M->C +merged L into C + A->G B->C C->C D->C E->G F->G G->G H->H I->I J->C K->C L->C M->C +merged G into I + A->I B->C C->C D->C E->I F->I G->I H->H I->I J->C K->C L->C M->C +merged I into H + A->H B->C C->C D->C E->H F->H G->H H->H I->H J->C K->C L->C M->C +merged C into H + A->H B->H C->H D->H E->H F->H G->H H->H I->H J->H K->H L->H M->H """ # Emacs turd ' @@ -493,7 +493,7 @@ fun_tests = """ Build up to a recursive Sieve of Eratosthenes generator. >>> def firstn(g, n): -... return [g.next() for i in range(n)] +... return [next(g) for i in range(n)] >>> def intsfrom(i): ... while 1: @@ -512,7 +512,7 @@ Build up to a recursive Sieve of Eratosthenes generator. [1, 2, 4, 5, 7, 8] >>> def sieve(ints): -... prime = ints.next() +... prime = next(ints) ... yield prime ... not_divisible_by_prime = exclude_multiples(prime, ints) ... for p in sieve(not_divisible_by_prime): @@ -536,19 +536,19 @@ Try writing it without generators, and correctly, and without generating [10, 20, 30, 40, 50, 60, 70, 80, 90, 100] >>> def merge(g, h): -... ng = g.next() -... nh = h.next() +... ng = next(g) +... nh = next(h) ... while 1: ... if ng < nh: ... yield ng -... ng = g.next() +... ng = next(g) ... elif ng > nh: ... yield nh -... nh = h.next() +... nh = next(h) ... else: ... yield ng -... ng = g.next() -... nh = h.next() +... ng = next(g) +... nh = next(h) The following works, but is doing a whale of a lot of redundant work -- it's not clear how to get the internal uses of m235 to share a single @@ -576,7 +576,7 @@ address space, and it *looked* like a very slow leak. >>> result = m235() >>> for i in range(3): -... print firstn(result, 15) +... print(firstn(result, 15)) [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24] [25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80] [81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192] @@ -589,7 +589,7 @@ arguments are iterable -- a LazyList is the same as a generator to times(). >>> class LazyList: ... def __init__(self, g): ... self.sofar = [] -... self.fetch = g.next +... self.fetch = g.__next__ ... ... def __getitem__(self, i): ... sofar, fetch = self.sofar, self.fetch @@ -613,7 +613,7 @@ efficient. >>> m235 = LazyList(m235()) >>> for i in range(5): -... print [m235[j] for j in range(15*i, 15*(i+1))] +... print([m235[j] for j in range(15*i, 15*(i+1))]) [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24] [25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80] [81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192] @@ -626,10 +626,10 @@ Ye olde Fibonacci generator, LazyList style. ... ... def sum(g, h): ... while 1: -... yield g.next() + h.next() +... yield next(g) + next(h) ... ... def tail(g): -... g.next() # throw first away +... next(g) # throw first away ... for x in g: ... yield x ... @@ -684,7 +684,7 @@ m235 to share a single generator". >>> it = m235() >>> for i in range(5): -... print firstn(it, 15) +... print(firstn(it, 15)) [1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24] [25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80] [81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192] @@ -705,12 +705,12 @@ Ye olde Fibonacci generator, tee style. ... ... def _isum(g, h): ... while 1: -... yield g.next() + h.next() +... yield next(g) + next(h) ... ... def _fib(): ... yield 1 ... yield 2 -... fibTail.next() # throw first away +... next(fibTail) # throw first away ... for res in _isum(fibHead, fibTail): ... yield res ... @@ -733,14 +733,14 @@ syntax_tests = """ ... yield 1 Traceback (most recent call last): .. -SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[0]>, line 3) +SyntaxError: 'return' with argument inside generator >>> def f(): ... yield 1 ... return 22 Traceback (most recent call last): .. -SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[1]>, line 3) +SyntaxError: 'return' with argument inside generator "return None" is not the same as "return" in a generator: @@ -749,7 +749,7 @@ SyntaxError: 'return' with argument inside generator (<doctest test.test_generat ... return None Traceback (most recent call last): .. -SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[2]>, line 3) +SyntaxError: 'return' with argument inside generator These are fine: @@ -794,27 +794,27 @@ These are fine: >>> def f(): ... yield >>> type(f()) -<type 'generator'> +<class 'generator'> >>> def f(): ... if 0: ... yield >>> type(f()) -<type 'generator'> +<class 'generator'> >>> def f(): ... if 0: ... yield 1 >>> type(f()) -<type 'generator'> +<class 'generator'> >>> def f(): ... if "": ... yield None >>> type(f()) -<type 'generator'> +<class 'generator'> >>> def f(): ... return @@ -838,7 +838,7 @@ These are fine: ... x = 1 ... return >>> type(f()) -<type 'generator'> +<class 'generator'> >>> def f(): ... if 0: @@ -846,7 +846,7 @@ These are fine: ... yield 1 ... >>> type(f()) -<type 'NoneType'> +<class 'NoneType'> >>> def f(): ... if 0: @@ -856,7 +856,7 @@ These are fine: ... def f(self): ... yield 2 >>> type(f()) -<type 'NoneType'> +<class 'NoneType'> >>> def f(): ... if 0: @@ -864,7 +864,7 @@ These are fine: ... if 0: ... yield 2 >>> type(f()) -<type 'generator'> +<class 'generator'> >>> def f(): @@ -878,7 +878,7 @@ These are fine: ... if 0: ... yield 2 # because it's a generator (line 10) Traceback (most recent call last): -SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.syntax[24]>, line 10) +SyntaxError: 'return' with argument inside generator This one caused a crash (see SF bug 567538): @@ -890,13 +890,13 @@ This one caused a crash (see SF bug 567538): ... yield i ... >>> g = f() ->>> print g.next() +>>> print(next(g)) 0 ->>> print g.next() +>>> print(next(g)) 1 ->>> print g.next() +>>> print(next(g)) 2 ->>> print g.next() +>>> print(next(g)) Traceback (most recent call last): StopIteration @@ -907,14 +907,14 @@ Test the gi_code attribute ... yield 5 ... >>> g = f() ->>> g.gi_code is f.func_code +>>> g.gi_code is f.__code__ True ->>> g.next() +>>> next(g) 5 ->>> g.next() +>>> next(g) Traceback (most recent call last): StopIteration ->>> g.gi_code is f.func_code +>>> g.gi_code is f.__code__ True @@ -1052,7 +1052,7 @@ def flat_conjoin(gs): # rename to conjoin to run tests with this instead # Descend. try: while i < n: - it = iters[i] = gs[i]().next + it = iters[i] = gs[i]().__next__ values[i] = it() i += 1 except _StopIteration: @@ -1096,9 +1096,9 @@ class Queens: # generates the possiblities for the columns in that row. self.rowgenerators = [] for i in rangen: - rowuses = [(1L << j) | # column ordinal - (1L << (n + i-j + n-1)) | # NW-SE ordinal - (1L << (n + 2*n-1 + i+j)) # NE-SW ordinal + rowuses = [(1 << j) | # column ordinal + (1 << (n + i-j + n-1)) | # NW-SE ordinal + (1 << (n + 2*n-1 + i+j)) # NE-SW ordinal for j in rangen] def rowgen(rowuses=rowuses): @@ -1121,12 +1121,12 @@ class Queens: n = self.n assert n == len(row2col) sep = "+" + "-+" * n - print sep + print(sep) for i in range(n): squares = [" " for j in range(n)] squares[row2col[i]] = "Q" - print "|" + "|".join(squares) + "|" - print sep + print("|" + "|".join(squares) + "|") + print(sep) # A conjoin-based Knight's Tour solver. This is pretty sophisticated # (e.g., when used with flat_conjoin above, and passing hard=1 to the @@ -1318,11 +1318,11 @@ class Knights: k += 1 sep = "+" + ("-" * w + "+") * n - print sep + print(sep) for i in range(m): row = squares[i] - print "|" + "|".join(row) + "|" - print sep + print("|" + "|".join(row) + "|") + print(sep) conjoin_tests = """ @@ -1330,7 +1330,7 @@ Generate the 3-bit binary numbers in order. This illustrates dumbest- possible use of conjoin, just to generate the full cross-product. >>> for c in conjoin([lambda: iter((0, 1))] * 3): -... print c +... print(c) [0, 0, 0] [0, 0, 1] [0, 1, 0] @@ -1350,7 +1350,7 @@ generated sequence, you need to copy its results. >>> for n in range(10): ... all = list(gencopy(conjoin([lambda: iter((0, 1))] * n))) -... print n, len(all), all[0] == [0] * n, all[-1] == [1] * n +... print(n, len(all), all[0] == [0] * n, all[-1] == [1] * n) 0 1 True True 1 2 True True 2 4 True True @@ -1370,7 +1370,7 @@ And run an 8-queens solver. >>> for row2col in q.solve(): ... count += 1 ... if count <= LIMIT: -... print "Solution", count +... print("Solution", count) ... q.printsolution(row2col) Solution 1 +-+-+-+-+-+-+-+-+ @@ -1409,7 +1409,7 @@ Solution 2 | | | | |Q| | | | +-+-+-+-+-+-+-+-+ ->>> print count, "solutions in all." +>>> print(count, "solutions in all.") 92 solutions in all. And run a Knight's Tour on a 10x10 board. Note that there are about @@ -1421,7 +1421,7 @@ And run a Knight's Tour on a 10x10 board. Note that there are about >>> for x in k.solve(): ... count += 1 ... if count <= LIMIT: -... print "Solution", count +... print("Solution", count) ... k.printsolution(x) ... else: ... break @@ -1499,10 +1499,10 @@ coroutine_tests = """\ Sending a value into a started generator: >>> def f(): -... print (yield 1) +... print((yield 1)) ... yield 2 >>> g = f() ->>> g.next() +>>> next(g) 1 >>> g.send(42) 42 @@ -1533,7 +1533,7 @@ And a more sane, but still weird usage: >>> def f(): list(i for i in [(yield 26)]) >>> type(f()) -<type 'generator'> +<class 'generator'> A yield expression with augmented assignment. @@ -1545,17 +1545,17 @@ A yield expression with augmented assignment. ... seq.append(count) >>> seq = [] >>> c = coroutine(seq) ->>> c.next() ->>> print seq +>>> next(c) +>>> print(seq) [] >>> c.send(10) ->>> print seq +>>> print(seq) [10] >>> c.send(10) ->>> print seq +>>> print(seq) [10, 20] >>> c.send(10) ->>> print seq +>>> print(seq) [10, 20, 30] @@ -1564,30 +1564,26 @@ Check some syntax errors for yield expressions: >>> f=lambda: (yield 1),(yield 2) Traceback (most recent call last): ... - File "<doctest test.test_generators.__test__.coroutine[21]>", line 1 SyntaxError: 'yield' outside function >>> def f(): return lambda x=(yield): 1 Traceback (most recent call last): ... -SyntaxError: 'return' with argument inside generator (<doctest test.test_generators.__test__.coroutine[22]>, line 1) +SyntaxError: 'return' with argument inside generator >>> def f(): x = yield = y Traceback (most recent call last): ... - File "<doctest test.test_generators.__test__.coroutine[23]>", line 1 SyntaxError: assignment to yield expression not possible >>> def f(): (yield bar) = y Traceback (most recent call last): ... - File "<doctest test.test_generators.__test__.coroutine[24]>", line 1 SyntaxError: can't assign to yield expression >>> def f(): (yield bar) += y Traceback (most recent call last): ... - File "<doctest test.test_generators.__test__.coroutine[25]>", line 1 SyntaxError: can't assign to yield expression @@ -1596,12 +1592,12 @@ Now check some throw() conditions: >>> def f(): ... while True: ... try: -... print (yield) -... except ValueError,v: -... print "caught ValueError (%s)" % (v), +... print((yield)) +... except ValueError as v: +... print("caught ValueError (%s)" % (v)) >>> import sys >>> g = f() ->>> g.next() +>>> next(g) >>> g.throw(ValueError) # type only caught ValueError () @@ -1628,6 +1624,21 @@ Traceback (most recent call last): ... TypeError: throw() third argument must be a traceback object +>>> g.throw("abc") +Traceback (most recent call last): + ... +TypeError: exceptions must be classes or instances deriving from BaseException, not str + +>>> g.throw(0) +Traceback (most recent call last): + ... +TypeError: exceptions must be classes or instances deriving from BaseException, not int + +>>> g.throw(list) +Traceback (most recent call last): + ... +TypeError: exceptions must be classes or instances deriving from BaseException, not type + >>> def throw(g,exc): ... try: ... raise exc @@ -1644,7 +1655,7 @@ Traceback (most recent call last): ... TypeError ->>> print g.gi_frame +>>> print(g.gi_frame) None >>> g.send(2) @@ -1662,20 +1673,41 @@ Traceback (most recent call last): ... ValueError: 7 ->>> f().throw("abc") # throw on just-opened generator -Traceback (most recent call last): - ... -TypeError: exceptions must be classes, or instances, not str +Plain "raise" inside a generator should preserve the traceback (#13188). +The traceback should have 3 levels: +- g.throw() +- f() +- 1/0 + +>>> def f(): +... try: +... yield +... except: +... raise +>>> g = f() +>>> try: +... 1/0 +... except ZeroDivisionError as v: +... try: +... g.throw(v) +... except Exception as w: +... tb = w.__traceback__ +>>> levels = 0 +>>> while tb: +... levels += 1 +... tb = tb.tb_next +>>> levels +3 Now let's try closing a generator: >>> def f(): ... try: yield ... except GeneratorExit: -... print "exiting" +... print("exiting") >>> g = f() ->>> g.next() +>>> next(g) >>> g.close() exiting >>> g.close() # should be no-op now @@ -1685,7 +1717,7 @@ exiting >>> def f(): yield # an even simpler generator >>> f().close() # close before opening >>> g = f() ->>> g.next() +>>> next(g) >>> g.close() # close normally And finalization: @@ -1693,21 +1725,10 @@ And finalization: >>> def f(): ... try: yield ... finally: -... print "exiting" +... print("exiting") >>> g = f() ->>> g.next() ->>> del g -exiting - ->>> class context(object): -... def __enter__(self): pass -... def __exit__(self, *args): print 'exiting' ->>> def f(): -... with context(): -... yield ->>> g = f() ->>> g.next() +>>> next(g) >>> del g exiting @@ -1716,11 +1737,13 @@ GeneratorExit is not caught by except Exception: >>> def f(): ... try: yield -... except Exception: print 'except' -... finally: print 'finally' +... except Exception: +... print('except') +... finally: +... print('finally') >>> g = f() ->>> g.next() +>>> next(g) >>> del g finally @@ -1732,7 +1755,7 @@ Now let's try some ill-behaved generators: ... except GeneratorExit: ... yield "foo!" >>> g = f() ->>> g.next() +>>> next(g) >>> g.close() Traceback (most recent call last): ... @@ -1742,10 +1765,10 @@ RuntimeError: generator ignored GeneratorExit Our ill-behaved code should be invoked during GC: ->>> import sys, StringIO ->>> old, sys.stderr = sys.stderr, StringIO.StringIO() +>>> import sys, io +>>> old, sys.stderr = sys.stderr, io.StringIO() >>> g = f() ->>> g.next() +>>> next(g) >>> del g >>> sys.stderr.getvalue().startswith( ... "Exception RuntimeError: 'generator ignored GeneratorExit' in " @@ -1761,7 +1784,7 @@ And errors thrown during closing should propagate: ... except GeneratorExit: ... raise TypeError("fie!") >>> g = f() ->>> g.next() +>>> next(g) >>> g.close() Traceback (most recent call last): ... @@ -1773,25 +1796,25 @@ enclosing function a generator: >>> def f(): x += yield >>> type(f()) -<type 'generator'> +<class 'generator'> >>> def f(): x = yield >>> type(f()) -<type 'generator'> +<class 'generator'> >>> def f(): lambda x=(yield): 1 >>> type(f()) -<type 'generator'> +<class 'generator'> >>> def f(): x=(i for i in (yield) if (yield)) >>> type(f()) -<type 'generator'> +<class 'generator'> >>> def f(d): d[(yield "a")] = d[(yield "b")] = 27 >>> data = [1,2] >>> g = f(data) >>> type(g) -<type 'generator'> +<class 'generator'> >>> g.send(None) 'a' >>> data @@ -1817,7 +1840,7 @@ would trigger if it starts being uncleanable again. ... class gen: ... def __iter__(self): ... return self -... def next(self): +... def __next__(self): ... return self.item ... g = gen() ... head, tail = itertools.tee(g) @@ -1828,7 +1851,7 @@ would trigger if it starts being uncleanable again. Make sure to also test the involvement of the tee-internal teedataobject, which stores returned items. ->>> item = it.next() +>>> item = next(it) @@ -1853,10 +1876,10 @@ explicitly, without generators. We do have to redirect stderr to avoid printing warnings and to doublecheck that we actually tested what we wanted to test. ->>> import sys, StringIO +>>> import sys, io >>> old = sys.stderr >>> try: -... sys.stderr = StringIO.StringIO() +... sys.stderr = io.StringIO() ... class Leaker: ... def __del__(self): ... raise RuntimeError @@ -1898,8 +1921,8 @@ __test__ = {"tut": tutorial_tests, # Note that doctest and regrtest both look in sys.argv for a "-v" argument, # so this works as expected in both ways of running regrtest. def test_main(verbose=None): - from test import test_support, test_generators - test_support.run_doctest(test_generators, verbose) + from test import support, test_generators + support.run_doctest(test_generators, verbose) # This part isn't needed for regrtest, but for running the test directly. if __name__ == "__main__": |