aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/test/test_generators.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_generators.py')
-rw-r--r--Lib/test/test_generators.py369
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__":