Skip to content

Commit 4b9416a

Browse files
authored
Update test_genexps.py & test_metaclass.py to 3.14.5 (#7884)
* Update `test_genexps.py` to 3.14.5 * Align `test_metaclass.py` with the new doctest checker
1 parent 2d8f8ab commit 4b9416a

2 files changed

Lines changed: 306 additions & 30 deletions

File tree

Lib/test/test_genexps.py

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

0 commit comments

Comments
 (0)