|
1 doctests = """ |
|
2 |
|
3 Test simple loop with conditional |
|
4 |
|
5 >>> sum(i*i for i in range(100) if i&1 == 1) |
|
6 166650 |
|
7 |
|
8 Test simple nesting |
|
9 |
|
10 >>> list((i,j) for i in range(3) for j in range(4) ) |
|
11 [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)] |
|
12 |
|
13 Test nesting with the inner expression dependent on the outer |
|
14 |
|
15 >>> list((i,j) for i in range(4) for j in range(i) ) |
|
16 [(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2)] |
|
17 |
|
18 Make sure the induction variable is not exposed |
|
19 |
|
20 >>> i = 20 |
|
21 >>> sum(i*i for i in range(100)) |
|
22 328350 |
|
23 >>> i |
|
24 20 |
|
25 |
|
26 Test first class |
|
27 |
|
28 >>> g = (i*i for i in range(4)) |
|
29 >>> type(g) |
|
30 <type 'generator'> |
|
31 >>> list(g) |
|
32 [0, 1, 4, 9] |
|
33 |
|
34 Test direct calls to next() |
|
35 |
|
36 >>> g = (i*i for i in range(3)) |
|
37 >>> g.next() |
|
38 0 |
|
39 >>> g.next() |
|
40 1 |
|
41 >>> g.next() |
|
42 4 |
|
43 >>> g.next() |
|
44 Traceback (most recent call last): |
|
45 File "<pyshell#21>", line 1, in -toplevel- |
|
46 g.next() |
|
47 StopIteration |
|
48 |
|
49 Does it stay stopped? |
|
50 |
|
51 >>> g.next() |
|
52 Traceback (most recent call last): |
|
53 File "<pyshell#21>", line 1, in -toplevel- |
|
54 g.next() |
|
55 StopIteration |
|
56 >>> list(g) |
|
57 [] |
|
58 |
|
59 Test running gen when defining function is out of scope |
|
60 |
|
61 >>> def f(n): |
|
62 ... return (i*i for i in xrange(n)) |
|
63 >>> list(f(10)) |
|
64 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] |
|
65 |
|
66 >>> def f(n): |
|
67 ... return ((i,j) for i in xrange(3) for j in xrange(n)) |
|
68 >>> list(f(4)) |
|
69 [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)] |
|
70 >>> def f(n): |
|
71 ... return ((i,j) for i in xrange(3) for j in xrange(4) if j in xrange(n)) |
|
72 >>> list(f(4)) |
|
73 [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)] |
|
74 >>> list(f(2)) |
|
75 [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)] |
|
76 |
|
77 Verify that parenthesis are required in a statement |
|
78 |
|
79 >>> def f(n): |
|
80 ... return i*i for i in xrange(n) |
|
81 Traceback (most recent call last): |
|
82 ... |
|
83 SyntaxError: invalid syntax |
|
84 |
|
85 Verify that parenthesis are required when used as a keyword argument value |
|
86 |
|
87 >>> dict(a = i for i in xrange(10)) |
|
88 Traceback (most recent call last): |
|
89 ... |
|
90 SyntaxError: invalid syntax |
|
91 |
|
92 Verify that parenthesis are required when used as a keyword argument value |
|
93 |
|
94 >>> dict(a = (i for i in xrange(10))) #doctest: +ELLIPSIS |
|
95 {'a': <generator object at ...>} |
|
96 |
|
97 Verify early binding for the outermost for-expression |
|
98 |
|
99 >>> x=10 |
|
100 >>> g = (i*i for i in range(x)) |
|
101 >>> x = 5 |
|
102 >>> list(g) |
|
103 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] |
|
104 |
|
105 Verify that the outermost for-expression makes an immediate check |
|
106 for iterability |
|
107 |
|
108 >>> (i for i in 6) |
|
109 Traceback (most recent call last): |
|
110 File "<pyshell#4>", line 1, in -toplevel- |
|
111 (i for i in 6) |
|
112 TypeError: 'int' object is not iterable |
|
113 |
|
114 Verify late binding for the outermost if-expression |
|
115 |
|
116 >>> include = (2,4,6,8) |
|
117 >>> g = (i*i for i in range(10) if i in include) |
|
118 >>> include = (1,3,5,7,9) |
|
119 >>> list(g) |
|
120 [1, 9, 25, 49, 81] |
|
121 |
|
122 Verify late binding for the innermost for-expression |
|
123 |
|
124 >>> g = ((i,j) for i in range(3) for j in range(x)) |
|
125 >>> x = 4 |
|
126 >>> list(g) |
|
127 [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)] |
|
128 |
|
129 Verify re-use of tuples (a side benefit of using genexps over listcomps) |
|
130 |
|
131 >>> tupleids = map(id, ((i,i) for i in xrange(10))) |
|
132 >>> int(max(tupleids) - min(tupleids)) |
|
133 0 |
|
134 |
|
135 Verify that syntax error's are raised for genexps used as lvalues |
|
136 |
|
137 >>> (y for y in (1,2)) = 10 |
|
138 Traceback (most recent call last): |
|
139 ... |
|
140 SyntaxError: can't assign to generator expression (<doctest test.test_genexps.__test__.doctests[40]>, line 1) |
|
141 |
|
142 >>> (y for y in (1,2)) += 10 |
|
143 Traceback (most recent call last): |
|
144 ... |
|
145 SyntaxError: augmented assignment to generator expression not possible (<doctest test.test_genexps.__test__.doctests[41]>, line 1) |
|
146 |
|
147 |
|
148 ########### Tests borrowed from or inspired by test_generators.py ############ |
|
149 |
|
150 Make a generator that acts like range() |
|
151 |
|
152 >>> yrange = lambda n: (i for i in xrange(n)) |
|
153 >>> list(yrange(10)) |
|
154 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] |
|
155 |
|
156 Generators always return to the most recent caller: |
|
157 |
|
158 >>> def creator(): |
|
159 ... r = yrange(5) |
|
160 ... print "creator", r.next() |
|
161 ... return r |
|
162 >>> def caller(): |
|
163 ... r = creator() |
|
164 ... for i in r: |
|
165 ... print "caller", i |
|
166 >>> caller() |
|
167 creator 0 |
|
168 caller 1 |
|
169 caller 2 |
|
170 caller 3 |
|
171 caller 4 |
|
172 |
|
173 Generators can call other generators: |
|
174 |
|
175 >>> def zrange(n): |
|
176 ... for i in yrange(n): |
|
177 ... yield i |
|
178 >>> list(zrange(5)) |
|
179 [0, 1, 2, 3, 4] |
|
180 |
|
181 |
|
182 Verify that a gen exp cannot be resumed while it is actively running: |
|
183 |
|
184 >>> g = (me.next() for i in xrange(10)) |
|
185 >>> me = g |
|
186 >>> me.next() |
|
187 Traceback (most recent call last): |
|
188 File "<pyshell#30>", line 1, in -toplevel- |
|
189 me.next() |
|
190 File "<pyshell#28>", line 1, in <generator expression> |
|
191 g = (me.next() for i in xrange(10)) |
|
192 ValueError: generator already executing |
|
193 |
|
194 Verify exception propagation |
|
195 |
|
196 >>> g = (10 // i for i in (5, 0, 2)) |
|
197 >>> g.next() |
|
198 2 |
|
199 >>> g.next() |
|
200 Traceback (most recent call last): |
|
201 File "<pyshell#37>", line 1, in -toplevel- |
|
202 g.next() |
|
203 File "<pyshell#35>", line 1, in <generator expression> |
|
204 g = (10 // i for i in (5, 0, 2)) |
|
205 ZeroDivisionError: integer division or modulo by zero |
|
206 >>> g.next() |
|
207 Traceback (most recent call last): |
|
208 File "<pyshell#38>", line 1, in -toplevel- |
|
209 g.next() |
|
210 StopIteration |
|
211 |
|
212 Make sure that None is a valid return value |
|
213 |
|
214 >>> list(None for i in xrange(10)) |
|
215 [None, None, None, None, None, None, None, None, None, None] |
|
216 |
|
217 Check that generator attributes are present |
|
218 |
|
219 >>> g = (i*i for i in range(3)) |
|
220 >>> expected = set(['gi_frame', 'gi_running', 'next']) |
|
221 >>> set(attr for attr in dir(g) if not attr.startswith('__')) >= expected |
|
222 True |
|
223 |
|
224 >>> print g.next.__doc__ |
|
225 x.next() -> the next value, or raise StopIteration |
|
226 >>> import types |
|
227 >>> isinstance(g, types.GeneratorType) |
|
228 True |
|
229 |
|
230 Check the __iter__ slot is defined to return self |
|
231 |
|
232 >>> iter(g) is g |
|
233 True |
|
234 |
|
235 Verify that the running flag is set properly |
|
236 |
|
237 >>> g = (me.gi_running for i in (0,1)) |
|
238 >>> me = g |
|
239 >>> me.gi_running |
|
240 0 |
|
241 >>> me.next() |
|
242 1 |
|
243 >>> me.gi_running |
|
244 0 |
|
245 |
|
246 Verify that genexps are weakly referencable |
|
247 |
|
248 >>> import weakref |
|
249 >>> g = (i*i for i in range(4)) |
|
250 >>> wr = weakref.ref(g) |
|
251 >>> wr() is g |
|
252 True |
|
253 >>> p = weakref.proxy(g) |
|
254 >>> list(p) |
|
255 [0, 1, 4, 9] |
|
256 |
|
257 |
|
258 """ |
|
259 |
|
260 |
|
261 __test__ = {'doctests' : doctests} |
|
262 |
|
263 def test_main(verbose=None): |
|
264 import sys |
|
265 from test import test_support |
|
266 from test import test_genexps |
|
267 test_support.run_doctest(test_genexps, verbose) |
|
268 |
|
269 # verify reference counting |
|
270 if verbose and hasattr(sys, "gettotalrefcount"): |
|
271 import gc |
|
272 counts = [None] * 5 |
|
273 for i in xrange(len(counts)): |
|
274 test_support.run_doctest(test_genexps, verbose) |
|
275 gc.collect() |
|
276 counts[i] = sys.gettotalrefcount() |
|
277 print counts |
|
278 |
|
279 if __name__ == "__main__": |
|
280 test_main(verbose=True) |