|
1 from test.test_support import verify, TestFailed, check_syntax, vereq |
|
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 vereq(inc(1), 2) |
|
17 vereq(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 vereq(inc(1), 2) |
|
32 vereq(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 vereq(inc(1), 2) |
|
46 vereq(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 vereq(adder(1), 2) |
|
62 |
|
63 global_x = 10 |
|
64 vereq(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 vereq(inc(1), 2) |
|
78 vereq(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 vereq(inc(1), 11) # there's only one global |
|
93 vereq(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 vereq(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 vereq(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 vereq(t.test(), "var") |
|
145 vereq(t.method_and_var(), "method") |
|
146 vereq(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 vereq(t.test(), "var") |
|
162 vereq(t.method_and_var(), "method") |
|
163 vereq(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 vereq(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 vereq(inc(1), 2) |
|
256 vereq(plus10(5), 15) |
|
257 |
|
258 f2 = lambda x: (lambda : lambda y: x + y)() |
|
259 inc = f2(1) |
|
260 plus10 = f2(10) |
|
261 vereq(inc(1), 2) |
|
262 vereq(plus10(5), 15) |
|
263 |
|
264 f3 = lambda x: lambda y: global_x + y |
|
265 global_x = 1 |
|
266 inc = f3(None) |
|
267 vereq(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 vereq(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 # test for bug #1501934: incorrect LOAD/STORE_GLOBAL generation |
|
303 global_x = 1 |
|
304 def f(): |
|
305 global_x += 1 |
|
306 try: |
|
307 f() |
|
308 except UnboundLocalError: |
|
309 pass |
|
310 else: |
|
311 raise TestFailed, 'scope of global_x not correctly determined' |
|
312 |
|
313 print "14. complex definitions" |
|
314 |
|
315 def makeReturner(*lst): |
|
316 def returner(): |
|
317 return lst |
|
318 return returner |
|
319 |
|
320 vereq(makeReturner(1,2,3)(), (1,2,3)) |
|
321 |
|
322 def makeReturner2(**kwargs): |
|
323 def returner(): |
|
324 return kwargs |
|
325 return returner |
|
326 |
|
327 vereq(makeReturner2(a=11)()['a'], 11) |
|
328 |
|
329 def makeAddPair((a, b)): |
|
330 def addPair((c, d)): |
|
331 return (a + c, b + d) |
|
332 return addPair |
|
333 |
|
334 vereq(makeAddPair((1, 2))((100, 200)), (101,202)) |
|
335 |
|
336 print "15. scope of global statements" |
|
337 # Examples posted by Samuele Pedroni to python-dev on 3/1/2001 |
|
338 |
|
339 # I |
|
340 x = 7 |
|
341 def f(): |
|
342 x = 1 |
|
343 def g(): |
|
344 global x |
|
345 def i(): |
|
346 def h(): |
|
347 return x |
|
348 return h() |
|
349 return i() |
|
350 return g() |
|
351 vereq(f(), 7) |
|
352 vereq(x, 7) |
|
353 |
|
354 # II |
|
355 x = 7 |
|
356 def f(): |
|
357 x = 1 |
|
358 def g(): |
|
359 x = 2 |
|
360 def i(): |
|
361 def h(): |
|
362 return x |
|
363 return h() |
|
364 return i() |
|
365 return g() |
|
366 vereq(f(), 2) |
|
367 vereq(x, 7) |
|
368 |
|
369 # III |
|
370 x = 7 |
|
371 def f(): |
|
372 x = 1 |
|
373 def g(): |
|
374 global x |
|
375 x = 2 |
|
376 def i(): |
|
377 def h(): |
|
378 return x |
|
379 return h() |
|
380 return i() |
|
381 return g() |
|
382 vereq(f(), 2) |
|
383 vereq(x, 2) |
|
384 |
|
385 # IV |
|
386 x = 7 |
|
387 def f(): |
|
388 x = 3 |
|
389 def g(): |
|
390 global x |
|
391 x = 2 |
|
392 def i(): |
|
393 def h(): |
|
394 return x |
|
395 return h() |
|
396 return i() |
|
397 return g() |
|
398 vereq(f(), 2) |
|
399 vereq(x, 2) |
|
400 |
|
401 # XXX what about global statements in class blocks? |
|
402 # do they affect methods? |
|
403 |
|
404 x = 12 |
|
405 class Global: |
|
406 global x |
|
407 x = 13 |
|
408 def set(self, val): |
|
409 x = val |
|
410 def get(self): |
|
411 return x |
|
412 |
|
413 g = Global() |
|
414 vereq(g.get(), 13) |
|
415 g.set(15) |
|
416 vereq(g.get(), 13) |
|
417 |
|
418 print "16. check leaks" |
|
419 |
|
420 class Foo: |
|
421 count = 0 |
|
422 |
|
423 def __init__(self): |
|
424 Foo.count += 1 |
|
425 |
|
426 def __del__(self): |
|
427 Foo.count -= 1 |
|
428 |
|
429 def f1(): |
|
430 x = Foo() |
|
431 def f2(): |
|
432 return x |
|
433 f2() |
|
434 |
|
435 for i in range(100): |
|
436 f1() |
|
437 |
|
438 vereq(Foo.count, 0) |
|
439 |
|
440 print "17. class and global" |
|
441 |
|
442 def test(x): |
|
443 class Foo: |
|
444 global x |
|
445 def __call__(self, y): |
|
446 return x + y |
|
447 return Foo() |
|
448 |
|
449 x = 0 |
|
450 vereq(test(6)(2), 8) |
|
451 x = -1 |
|
452 vereq(test(3)(2), 5) |
|
453 |
|
454 looked_up_by_load_name = False |
|
455 class X: |
|
456 # Implicit globals inside classes are be looked up by LOAD_NAME, not |
|
457 # LOAD_GLOBAL. |
|
458 locals()['looked_up_by_load_name'] = True |
|
459 passed = looked_up_by_load_name |
|
460 |
|
461 verify(X.passed) |
|
462 |
|
463 print "18. verify that locals() works" |
|
464 |
|
465 def f(x): |
|
466 def g(y): |
|
467 def h(z): |
|
468 return y + z |
|
469 w = x + y |
|
470 y += 3 |
|
471 return locals() |
|
472 return g |
|
473 |
|
474 d = f(2)(4) |
|
475 verify(d.has_key('h')) |
|
476 del d['h'] |
|
477 vereq(d, {'x': 2, 'y': 7, 'w': 6}) |
|
478 |
|
479 print "19. var is bound and free in class" |
|
480 |
|
481 def f(x): |
|
482 class C: |
|
483 def m(self): |
|
484 return x |
|
485 a = x |
|
486 return C |
|
487 |
|
488 inst = f(3)() |
|
489 vereq(inst.a, inst.m()) |
|
490 |
|
491 print "20. interaction with trace function" |
|
492 |
|
493 import sys |
|
494 def tracer(a,b,c): |
|
495 return tracer |
|
496 |
|
497 def adaptgetter(name, klass, getter): |
|
498 kind, des = getter |
|
499 if kind == 1: # AV happens when stepping from this line to next |
|
500 if des == "": |
|
501 des = "_%s__%s" % (klass.__name__, name) |
|
502 return lambda obj: getattr(obj, des) |
|
503 |
|
504 class TestClass: |
|
505 pass |
|
506 |
|
507 sys.settrace(tracer) |
|
508 adaptgetter("foo", TestClass, (1, "")) |
|
509 sys.settrace(None) |
|
510 |
|
511 try: sys.settrace() |
|
512 except TypeError: pass |
|
513 else: raise TestFailed, 'sys.settrace() did not raise TypeError' |
|
514 |
|
515 print "20. eval and exec with free variables" |
|
516 |
|
517 def f(x): |
|
518 return lambda: x + 1 |
|
519 |
|
520 g = f(3) |
|
521 try: |
|
522 eval(g.func_code) |
|
523 except TypeError: |
|
524 pass |
|
525 else: |
|
526 print "eval() should have failed, because code contained free vars" |
|
527 |
|
528 try: |
|
529 exec g.func_code |
|
530 except TypeError: |
|
531 pass |
|
532 else: |
|
533 print "exec should have failed, because code contained free vars" |
|
534 |
|
535 print "21. list comprehension with local variables" |
|
536 |
|
537 try: |
|
538 print bad |
|
539 except NameError: |
|
540 pass |
|
541 else: |
|
542 print "bad should not be defined" |
|
543 |
|
544 def x(): |
|
545 [bad for s in 'a b' for bad in s.split()] |
|
546 |
|
547 x() |
|
548 try: |
|
549 print bad |
|
550 except NameError: |
|
551 pass |
|
552 |
|
553 print "22. eval with free variables" |
|
554 |
|
555 def f(x): |
|
556 def g(): |
|
557 x |
|
558 eval("x + 1") |
|
559 return g |
|
560 |
|
561 f(4)() |