Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | from test.test_support import verify, TestFailed, check_syntax |
2 | ||
3 | import warnings | |
4 | warnings.filterwarnings("ignore", r"import \*", SyntaxWarning, "<string>") | |
5 | ||
6 | print "1. simple nesting" | |
7 | ||
8 | def make_adder(x): | |
9 | def adder(y): | |
10 | return x + y | |
11 | return adder | |
12 | ||
13 | inc = make_adder(1) | |
14 | plus10 = make_adder(10) | |
15 | ||
16 | verify(inc(1) == 2) | |
17 | verify(plus10(-2) == 8) | |
18 | ||
19 | print "2. extra nesting" | |
20 | ||
21 | def make_adder2(x): | |
22 | def extra(): # check freevars passing through non-use scopes | |
23 | def adder(y): | |
24 | return x + y | |
25 | return adder | |
26 | return extra() | |
27 | ||
28 | inc = make_adder2(1) | |
29 | plus10 = make_adder2(10) | |
30 | ||
31 | verify(inc(1) == 2) | |
32 | verify(plus10(-2) == 8) | |
33 | ||
34 | print "3. simple nesting + rebinding" | |
35 | ||
36 | def make_adder3(x): | |
37 | def adder(y): | |
38 | return x + y | |
39 | x = x + 1 # check tracking of assignment to x in defining scope | |
40 | return adder | |
41 | ||
42 | inc = make_adder3(0) | |
43 | plus10 = make_adder3(9) | |
44 | ||
45 | verify(inc(1) == 2) | |
46 | verify(plus10(-2) == 8) | |
47 | ||
48 | print "4. nesting with global but no free" | |
49 | ||
50 | def make_adder4(): # XXX add exta level of indirection | |
51 | def nest(): | |
52 | def nest(): | |
53 | def adder(y): | |
54 | return global_x + y # check that plain old globals work | |
55 | return adder | |
56 | return nest() | |
57 | return nest() | |
58 | ||
59 | global_x = 1 | |
60 | adder = make_adder4() | |
61 | verify(adder(1) == 2) | |
62 | ||
63 | global_x = 10 | |
64 | verify(adder(-2) == 8) | |
65 | ||
66 | print "5. nesting through class" | |
67 | ||
68 | def make_adder5(x): | |
69 | class Adder: | |
70 | def __call__(self, y): | |
71 | return x + y | |
72 | return Adder() | |
73 | ||
74 | inc = make_adder5(1) | |
75 | plus10 = make_adder5(10) | |
76 | ||
77 | verify(inc(1) == 2) | |
78 | verify(plus10(-2) == 8) | |
79 | ||
80 | print "6. nesting plus free ref to global" | |
81 | ||
82 | def make_adder6(x): | |
83 | global global_nest_x | |
84 | def adder(y): | |
85 | return global_nest_x + y | |
86 | global_nest_x = x | |
87 | return adder | |
88 | ||
89 | inc = make_adder6(1) | |
90 | plus10 = make_adder6(10) | |
91 | ||
92 | verify(inc(1) == 11) # there's only one global | |
93 | verify(plus10(-2) == 8) | |
94 | ||
95 | print "7. nearest enclosing scope" | |
96 | ||
97 | def f(x): | |
98 | def g(y): | |
99 | x = 42 # check that this masks binding in f() | |
100 | def h(z): | |
101 | return x + z | |
102 | return h | |
103 | return g(2) | |
104 | ||
105 | test_func = f(10) | |
106 | verify(test_func(5) == 47) | |
107 | ||
108 | print "8. mixed freevars and cellvars" | |
109 | ||
110 | def identity(x): | |
111 | return x | |
112 | ||
113 | def f(x, y, z): | |
114 | def g(a, b, c): | |
115 | a = a + x # 3 | |
116 | def h(): | |
117 | # z * (4 + 9) | |
118 | # 3 * 13 | |
119 | return identity(z * (b + y)) | |
120 | y = c + z # 9 | |
121 | return h | |
122 | return g | |
123 | ||
124 | g = f(1, 2, 3) | |
125 | h = g(2, 4, 6) | |
126 | verify(h() == 39) | |
127 | ||
128 | print "9. free variable in method" | |
129 | ||
130 | def test(): | |
131 | method_and_var = "var" | |
132 | class Test: | |
133 | def method_and_var(self): | |
134 | return "method" | |
135 | def test(self): | |
136 | return method_and_var | |
137 | def actual_global(self): | |
138 | return str("global") | |
139 | def str(self): | |
140 | return str(self) | |
141 | return Test() | |
142 | ||
143 | t = test() | |
144 | verify(t.test() == "var") | |
145 | verify(t.method_and_var() == "method") | |
146 | verify(t.actual_global() == "global") | |
147 | ||
148 | method_and_var = "var" | |
149 | class Test: | |
150 | # this class is not nested, so the rules are different | |
151 | def method_and_var(self): | |
152 | return "method" | |
153 | def test(self): | |
154 | return method_and_var | |
155 | def actual_global(self): | |
156 | return str("global") | |
157 | def str(self): | |
158 | return str(self) | |
159 | ||
160 | t = Test() | |
161 | verify(t.test() == "var") | |
162 | verify(t.method_and_var() == "method") | |
163 | verify(t.actual_global() == "global") | |
164 | ||
165 | print "10. recursion" | |
166 | ||
167 | def f(x): | |
168 | def fact(n): | |
169 | if n == 0: | |
170 | return 1 | |
171 | else: | |
172 | return n * fact(n - 1) | |
173 | if x >= 0: | |
174 | return fact(x) | |
175 | else: | |
176 | raise ValueError, "x must be >= 0" | |
177 | ||
178 | verify(f(6) == 720) | |
179 | ||
180 | ||
181 | print "11. unoptimized namespaces" | |
182 | ||
183 | check_syntax("""\ | |
184 | def unoptimized_clash1(strip): | |
185 | def f(s): | |
186 | from string import * | |
187 | return strip(s) # ambiguity: free or local | |
188 | return f | |
189 | """) | |
190 | ||
191 | check_syntax("""\ | |
192 | def unoptimized_clash2(): | |
193 | from string import * | |
194 | def f(s): | |
195 | return strip(s) # ambiguity: global or local | |
196 | return f | |
197 | """) | |
198 | ||
199 | check_syntax("""\ | |
200 | def unoptimized_clash2(): | |
201 | from string import * | |
202 | def g(): | |
203 | def f(s): | |
204 | return strip(s) # ambiguity: global or local | |
205 | return f | |
206 | """) | |
207 | ||
208 | # XXX could allow this for exec with const argument, but what's the point | |
209 | check_syntax("""\ | |
210 | def error(y): | |
211 | exec "a = 1" | |
212 | def f(x): | |
213 | return x + y | |
214 | return f | |
215 | """) | |
216 | ||
217 | check_syntax("""\ | |
218 | def f(x): | |
219 | def g(): | |
220 | return x | |
221 | del x # can't del name | |
222 | """) | |
223 | ||
224 | check_syntax("""\ | |
225 | def f(): | |
226 | def g(): | |
227 | from string import * | |
228 | return strip # global or local? | |
229 | """) | |
230 | ||
231 | # and verify a few cases that should work | |
232 | ||
233 | exec """ | |
234 | def noproblem1(): | |
235 | from string import * | |
236 | f = lambda x:x | |
237 | ||
238 | def noproblem2(): | |
239 | from string import * | |
240 | def f(x): | |
241 | return x + 1 | |
242 | ||
243 | def noproblem3(): | |
244 | from string import * | |
245 | def f(x): | |
246 | global y | |
247 | y = x | |
248 | """ | |
249 | ||
250 | print "12. lambdas" | |
251 | ||
252 | f1 = lambda x: lambda y: x + y | |
253 | inc = f1(1) | |
254 | plus10 = f1(10) | |
255 | verify(inc(1) == 2) | |
256 | verify(plus10(5) == 15) | |
257 | ||
258 | f2 = lambda x: (lambda : lambda y: x + y)() | |
259 | inc = f2(1) | |
260 | plus10 = f2(10) | |
261 | verify(inc(1) == 2) | |
262 | verify(plus10(5) == 15) | |
263 | ||
264 | f3 = lambda x: lambda y: global_x + y | |
265 | global_x = 1 | |
266 | inc = f3(None) | |
267 | verify(inc(2) == 3) | |
268 | ||
269 | f8 = lambda x, y, z: lambda a, b, c: lambda : z * (b + y) | |
270 | g = f8(1, 2, 3) | |
271 | h = g(2, 4, 6) | |
272 | verify(h() == 18) | |
273 | ||
274 | print "13. UnboundLocal" | |
275 | ||
276 | def errorInOuter(): | |
277 | print y | |
278 | def inner(): | |
279 | return y | |
280 | y = 1 | |
281 | ||
282 | def errorInInner(): | |
283 | def inner(): | |
284 | return y | |
285 | inner() | |
286 | y = 1 | |
287 | ||
288 | try: | |
289 | errorInOuter() | |
290 | except UnboundLocalError: | |
291 | pass | |
292 | else: | |
293 | raise TestFailed | |
294 | ||
295 | try: | |
296 | errorInInner() | |
297 | except NameError: | |
298 | pass | |
299 | else: | |
300 | raise TestFailed | |
301 | ||
302 | print "14. complex definitions" | |
303 | ||
304 | def makeReturner(*lst): | |
305 | def returner(): | |
306 | return lst | |
307 | return returner | |
308 | ||
309 | verify(makeReturner(1,2,3)() == (1,2,3)) | |
310 | ||
311 | def makeReturner2(**kwargs): | |
312 | def returner(): | |
313 | return kwargs | |
314 | return returner | |
315 | ||
316 | verify(makeReturner2(a=11)()['a'] == 11) | |
317 | ||
318 | def makeAddPair((a, b)): | |
319 | def addPair((c, d)): | |
320 | return (a + c, b + d) | |
321 | return addPair | |
322 | ||
323 | verify(makeAddPair((1, 2))((100, 200)) == (101,202)) | |
324 | ||
325 | print "15. scope of global statements" | |
326 | # Examples posted by Samuele Pedroni to python-dev on 3/1/2001 | |
327 | ||
328 | # I | |
329 | x = 7 | |
330 | def f(): | |
331 | x = 1 | |
332 | def g(): | |
333 | global x | |
334 | def i(): | |
335 | def h(): | |
336 | return x | |
337 | return h() | |
338 | return i() | |
339 | return g() | |
340 | verify(f() == 7) | |
341 | verify(x == 7) | |
342 | ||
343 | # II | |
344 | x = 7 | |
345 | def f(): | |
346 | x = 1 | |
347 | def g(): | |
348 | x = 2 | |
349 | def i(): | |
350 | def h(): | |
351 | return x | |
352 | return h() | |
353 | return i() | |
354 | return g() | |
355 | verify(f() == 2) | |
356 | verify(x == 7) | |
357 | ||
358 | # III | |
359 | x = 7 | |
360 | def f(): | |
361 | x = 1 | |
362 | def g(): | |
363 | global x | |
364 | x = 2 | |
365 | def i(): | |
366 | def h(): | |
367 | return x | |
368 | return h() | |
369 | return i() | |
370 | return g() | |
371 | verify(f() == 2) | |
372 | verify(x == 2) | |
373 | ||
374 | # IV | |
375 | x = 7 | |
376 | def f(): | |
377 | x = 3 | |
378 | def g(): | |
379 | global x | |
380 | x = 2 | |
381 | def i(): | |
382 | def h(): | |
383 | return x | |
384 | return h() | |
385 | return i() | |
386 | return g() | |
387 | verify(f() == 2) | |
388 | verify(x == 2) | |
389 | ||
390 | print "16. check leaks" | |
391 | ||
392 | class Foo: | |
393 | count = 0 | |
394 | ||
395 | def __init__(self): | |
396 | Foo.count += 1 | |
397 | ||
398 | def __del__(self): | |
399 | Foo.count -= 1 | |
400 | ||
401 | def f1(): | |
402 | x = Foo() | |
403 | def f2(): | |
404 | return x | |
405 | f2() | |
406 | ||
407 | for i in range(100): | |
408 | f1() | |
409 | ||
410 | verify(Foo.count == 0) | |
411 | ||
412 | print "17. class and global" | |
413 | ||
414 | def test(x): | |
415 | class Foo: | |
416 | global x | |
417 | def __call__(self, y): | |
418 | return x + y | |
419 | return Foo() | |
420 | ||
421 | x = 0 | |
422 | verify(test(6)(2) == 8) | |
423 | x = -1 | |
424 | verify(test(3)(2) == 5) | |
425 | ||
426 | print "18. verify that locals() works" | |
427 | ||
428 | def f(x): | |
429 | def g(y): | |
430 | def h(z): | |
431 | return y + z | |
432 | w = x + y | |
433 | y += 3 | |
434 | return locals() | |
435 | return g | |
436 | ||
437 | d = f(2)(4) | |
438 | verify(d.has_key('h')) | |
439 | del d['h'] | |
440 | verify(d == {'x': 2, 'y': 7, 'w': 6}) | |
441 | ||
442 | print "19. var is bound and free in class" | |
443 | ||
444 | def f(x): | |
445 | class C: | |
446 | def m(self): | |
447 | return x | |
448 | a = x | |
449 | return C | |
450 | ||
451 | inst = f(3)() | |
452 | verify(inst.a == inst.m()) | |
453 | ||
454 | print "20. interaction with trace function" | |
455 | ||
456 | import sys | |
457 | def tracer(a,b,c): | |
458 | return tracer | |
459 | ||
460 | def adaptgetter(name, klass, getter): | |
461 | kind, des = getter | |
462 | if kind == 1: # AV happens when stepping from this line to next | |
463 | if des == "": | |
464 | des = "_%s__%s" % (klass.__name__, name) | |
465 | return lambda obj: getattr(obj, des) | |
466 | ||
467 | class TestClass: | |
468 | pass | |
469 | ||
470 | sys.settrace(tracer) | |
471 | adaptgetter("foo", TestClass, (1, "")) | |
472 | sys.settrace(None) | |
473 | ||
474 | try: sys.settrace() | |
475 | except TypeError: pass | |
476 | else: raise TestFailed, 'sys.settrace() did not raise TypeError' | |
477 | ||
478 | print "20. eval and exec with free variables" | |
479 | ||
480 | def f(x): | |
481 | return lambda: x + 1 | |
482 | ||
483 | g = f(3) | |
484 | try: | |
485 | eval(g.func_code) | |
486 | except TypeError: | |
487 | pass | |
488 | else: | |
489 | print "eval() should have failed, because code contained free vars" | |
490 | ||
491 | try: | |
492 | exec g.func_code | |
493 | except TypeError: | |
494 | pass | |
495 | else: | |
496 | print "exec should have failed, because code contained free vars" | |
497 | ||
498 | print "21. list comprehension with local variables" | |
499 | ||
500 | try: | |
501 | print bad | |
502 | except NameError: | |
503 | pass | |
504 | else: | |
505 | print "bad should not be defined" | |
506 | ||
507 | def x(): | |
508 | [bad for s in 'a b' for bad in s.split()] | |
509 | ||
510 | x() | |
511 | try: | |
512 | print bad | |
513 | except NameError: | |
514 | pass | |
515 | ||
516 | print "22. eval with free variables" | |
517 | ||
518 | def f(x): | |
519 | def g(): | |
520 | x | |
521 | eval("x + 1") | |
522 | return g | |
523 | ||
524 | f(4)() |