move sections
[python/dscho.git] / Lib / test / test_scope.py
blobb1549ef43ebf43660da22d38aef87a08acb1686f
1 import unittest
2 from test.test_support import check_syntax_error, check_py3k_warnings, \
3 check_warnings, run_unittest
6 class ScopeTests(unittest.TestCase):
8 def testSimpleNesting(self):
10 def make_adder(x):
11 def adder(y):
12 return x + y
13 return adder
15 inc = make_adder(1)
16 plus10 = make_adder(10)
18 self.assertEqual(inc(1), 2)
19 self.assertEqual(plus10(-2), 8)
21 def testExtraNesting(self):
23 def make_adder2(x):
24 def extra(): # check freevars passing through non-use scopes
25 def adder(y):
26 return x + y
27 return adder
28 return extra()
30 inc = make_adder2(1)
31 plus10 = make_adder2(10)
33 self.assertEqual(inc(1), 2)
34 self.assertEqual(plus10(-2), 8)
36 def testSimpleAndRebinding(self):
38 def make_adder3(x):
39 def adder(y):
40 return x + y
41 x = x + 1 # check tracking of assignment to x in defining scope
42 return adder
44 inc = make_adder3(0)
45 plus10 = make_adder3(9)
47 self.assertEqual(inc(1), 2)
48 self.assertEqual(plus10(-2), 8)
50 def testNestingGlobalNoFree(self):
52 def make_adder4(): # XXX add exta level of indirection
53 def nest():
54 def nest():
55 def adder(y):
56 return global_x + y # check that plain old globals work
57 return adder
58 return nest()
59 return nest()
61 global_x = 1
62 adder = make_adder4()
63 self.assertEqual(adder(1), 2)
65 global_x = 10
66 self.assertEqual(adder(-2), 8)
68 def testNestingThroughClass(self):
70 def make_adder5(x):
71 class Adder:
72 def __call__(self, y):
73 return x + y
74 return Adder()
76 inc = make_adder5(1)
77 plus10 = make_adder5(10)
79 self.assertEqual(inc(1), 2)
80 self.assertEqual(plus10(-2), 8)
82 def testNestingPlusFreeRefToGlobal(self):
84 def make_adder6(x):
85 global global_nest_x
86 def adder(y):
87 return global_nest_x + y
88 global_nest_x = x
89 return adder
91 inc = make_adder6(1)
92 plus10 = make_adder6(10)
94 self.assertEqual(inc(1), 11) # there's only one global
95 self.assertEqual(plus10(-2), 8)
97 def testNearestEnclosingScope(self):
99 def f(x):
100 def g(y):
101 x = 42 # check that this masks binding in f()
102 def h(z):
103 return x + z
104 return h
105 return g(2)
107 test_func = f(10)
108 self.assertEqual(test_func(5), 47)
110 def testMixedFreevarsAndCellvars(self):
112 def identity(x):
113 return x
115 def f(x, y, z):
116 def g(a, b, c):
117 a = a + x # 3
118 def h():
119 # z * (4 + 9)
120 # 3 * 13
121 return identity(z * (b + y))
122 y = c + z # 9
123 return h
124 return g
126 g = f(1, 2, 3)
127 h = g(2, 4, 6)
128 self.assertEqual(h(), 39)
130 def testFreeVarInMethod(self):
132 def test():
133 method_and_var = "var"
134 class Test:
135 def method_and_var(self):
136 return "method"
137 def test(self):
138 return method_and_var
139 def actual_global(self):
140 return str("global")
141 def str(self):
142 return str(self)
143 return Test()
145 t = test()
146 self.assertEqual(t.test(), "var")
147 self.assertEqual(t.method_and_var(), "method")
148 self.assertEqual(t.actual_global(), "global")
150 method_and_var = "var"
151 class Test:
152 # this class is not nested, so the rules are different
153 def method_and_var(self):
154 return "method"
155 def test(self):
156 return method_and_var
157 def actual_global(self):
158 return str("global")
159 def str(self):
160 return str(self)
162 t = Test()
163 self.assertEqual(t.test(), "var")
164 self.assertEqual(t.method_and_var(), "method")
165 self.assertEqual(t.actual_global(), "global")
167 def testRecursion(self):
169 def f(x):
170 def fact(n):
171 if n == 0:
172 return 1
173 else:
174 return n * fact(n - 1)
175 if x >= 0:
176 return fact(x)
177 else:
178 raise ValueError, "x must be >= 0"
180 self.assertEqual(f(6), 720)
183 def testUnoptimizedNamespaces(self):
185 check_syntax_error(self, """\
186 def unoptimized_clash1(strip):
187 def f(s):
188 from string import *
189 return strip(s) # ambiguity: free or local
190 return f
191 """)
193 check_syntax_error(self, """\
194 def unoptimized_clash2():
195 from string import *
196 def f(s):
197 return strip(s) # ambiguity: global or local
198 return f
199 """)
201 check_syntax_error(self, """\
202 def unoptimized_clash2():
203 from string import *
204 def g():
205 def f(s):
206 return strip(s) # ambiguity: global or local
207 return f
208 """)
210 # XXX could allow this for exec with const argument, but what's the point
211 check_syntax_error(self, """\
212 def error(y):
213 exec "a = 1"
214 def f(x):
215 return x + y
216 return f
217 """)
219 check_syntax_error(self, """\
220 def f(x):
221 def g():
222 return x
223 del x # can't del name
224 """)
226 check_syntax_error(self, """\
227 def f():
228 def g():
229 from string import *
230 return strip # global or local?
231 """)
233 # and verify a few cases that should work
235 exec """
236 def noproblem1():
237 from string import *
238 f = lambda x:x
240 def noproblem2():
241 from string import *
242 def f(x):
243 return x + 1
245 def noproblem3():
246 from string import *
247 def f(x):
248 global y
249 y = x
252 def testLambdas(self):
254 f1 = lambda x: lambda y: x + y
255 inc = f1(1)
256 plus10 = f1(10)
257 self.assertEqual(inc(1), 2)
258 self.assertEqual(plus10(5), 15)
260 f2 = lambda x: (lambda : lambda y: x + y)()
261 inc = f2(1)
262 plus10 = f2(10)
263 self.assertEqual(inc(1), 2)
264 self.assertEqual(plus10(5), 15)
266 f3 = lambda x: lambda y: global_x + y
267 global_x = 1
268 inc = f3(None)
269 self.assertEqual(inc(2), 3)
271 f8 = lambda x, y, z: lambda a, b, c: lambda : z * (b + y)
272 g = f8(1, 2, 3)
273 h = g(2, 4, 6)
274 self.assertEqual(h(), 18)
276 def testUnboundLocal(self):
278 def errorInOuter():
279 print y
280 def inner():
281 return y
282 y = 1
284 def errorInInner():
285 def inner():
286 return y
287 inner()
288 y = 1
290 self.assertRaises(UnboundLocalError, errorInOuter)
291 self.assertRaises(NameError, errorInInner)
293 # test for bug #1501934: incorrect LOAD/STORE_GLOBAL generation
294 exec """
295 global_x = 1
296 def f():
297 global_x += 1
298 try:
300 except UnboundLocalError:
301 pass
302 else:
303 fail('scope of global_x not correctly determined')
304 """ in {'fail': self.fail}
306 def testComplexDefinitions(self):
308 def makeReturner(*lst):
309 def returner():
310 return lst
311 return returner
313 self.assertEqual(makeReturner(1,2,3)(), (1,2,3))
315 def makeReturner2(**kwargs):
316 def returner():
317 return kwargs
318 return returner
320 self.assertEqual(makeReturner2(a=11)()['a'], 11)
322 with check_py3k_warnings(("tuple parameter unpacking has been removed",
323 SyntaxWarning)):
324 exec """\
325 def makeAddPair((a, b)):
326 def addPair((c, d)):
327 return (a + c, b + d)
328 return addPair
329 """ in locals()
330 self.assertEqual(makeAddPair((1, 2))((100, 200)), (101,202))
332 def testScopeOfGlobalStmt(self):
333 # Examples posted by Samuele Pedroni to python-dev on 3/1/2001
335 exec """\
337 x = 7
338 def f():
339 x = 1
340 def g():
341 global x
342 def i():
343 def h():
344 return x
345 return h()
346 return i()
347 return g()
348 self.assertEqual(f(), 7)
349 self.assertEqual(x, 7)
351 # II
352 x = 7
353 def f():
354 x = 1
355 def g():
356 x = 2
357 def i():
358 def h():
359 return x
360 return h()
361 return i()
362 return g()
363 self.assertEqual(f(), 2)
364 self.assertEqual(x, 7)
366 # III
367 x = 7
368 def f():
369 x = 1
370 def g():
371 global x
372 x = 2
373 def i():
374 def h():
375 return x
376 return h()
377 return i()
378 return g()
379 self.assertEqual(f(), 2)
380 self.assertEqual(x, 2)
382 # IV
383 x = 7
384 def f():
385 x = 3
386 def g():
387 global x
388 x = 2
389 def i():
390 def h():
391 return x
392 return h()
393 return i()
394 return g()
395 self.assertEqual(f(), 2)
396 self.assertEqual(x, 2)
398 # XXX what about global statements in class blocks?
399 # do they affect methods?
401 x = 12
402 class Global:
403 global x
404 x = 13
405 def set(self, val):
406 x = val
407 def get(self):
408 return x
410 g = Global()
411 self.assertEqual(g.get(), 13)
412 g.set(15)
413 self.assertEqual(g.get(), 13)
416 def testLeaks(self):
418 class Foo:
419 count = 0
421 def __init__(self):
422 Foo.count += 1
424 def __del__(self):
425 Foo.count -= 1
427 def f1():
428 x = Foo()
429 def f2():
430 return x
431 f2()
433 for i in range(100):
434 f1()
436 self.assertEqual(Foo.count, 0)
438 def testClassAndGlobal(self):
440 exec """\
441 def test(x):
442 class Foo:
443 global x
444 def __call__(self, y):
445 return x + y
446 return Foo()
448 x = 0
449 self.assertEqual(test(6)(2), 8)
450 x = -1
451 self.assertEqual(test(3)(2), 5)
453 looked_up_by_load_name = False
454 class X:
455 # Implicit globals inside classes are be looked up by LOAD_NAME, not
456 # LOAD_GLOBAL.
457 locals()['looked_up_by_load_name'] = True
458 passed = looked_up_by_load_name
460 self.assertTrue(X.passed)
463 def testLocalsFunction(self):
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
474 d = f(2)(4)
475 self.assertIn('h', d)
476 del d['h']
477 self.assertEqual(d, {'x': 2, 'y': 7, 'w': 6})
479 def testLocalsClass(self):
480 # This test verifies that calling locals() does not pollute
481 # the local namespace of the class with free variables. Old
482 # versions of Python had a bug, where a free variable being
483 # passed through a class namespace would be inserted into
484 # locals() by locals() or exec or a trace function.
486 # The real bug lies in frame code that copies variables
487 # between fast locals and the locals dict, e.g. when executing
488 # a trace function.
490 def f(x):
491 class C:
492 x = 12
493 def m(self):
494 return x
495 locals()
496 return C
498 self.assertEqual(f(1).x, 12)
500 def f(x):
501 class C:
502 y = x
503 def m(self):
504 return x
505 z = list(locals())
506 return C
508 varnames = f(1).z
509 self.assertNotIn("x", varnames)
510 self.assertIn("y", varnames)
512 def testLocalsClass_WithTrace(self):
513 # Issue23728: after the trace function returns, the locals()
514 # dictionary is used to update all variables, this used to
515 # include free variables. But in class statements, free
516 # variables are not inserted...
517 import sys
518 sys.settrace(lambda a,b,c:None)
519 try:
520 x = 12
522 class C:
523 def f(self):
524 return x
526 self.assertEquals(x, 12) # Used to raise UnboundLocalError
527 finally:
528 sys.settrace(None)
530 def testBoundAndFree(self):
531 # var is bound and free in class
533 def f(x):
534 class C:
535 def m(self):
536 return x
537 a = x
538 return C
540 inst = f(3)()
541 self.assertEqual(inst.a, inst.m())
543 def testInteractionWithTraceFunc(self):
545 import sys
546 def tracer(a,b,c):
547 return tracer
549 def adaptgetter(name, klass, getter):
550 kind, des = getter
551 if kind == 1: # AV happens when stepping from this line to next
552 if des == "":
553 des = "_%s__%s" % (klass.__name__, name)
554 return lambda obj: getattr(obj, des)
556 class TestClass:
557 pass
559 sys.settrace(tracer)
560 adaptgetter("foo", TestClass, (1, ""))
561 sys.settrace(None)
563 self.assertRaises(TypeError, sys.settrace)
565 def testEvalExecFreeVars(self):
567 def f(x):
568 return lambda: x + 1
570 g = f(3)
571 self.assertRaises(TypeError, eval, g.func_code)
573 try:
574 exec g.func_code in {}
575 except TypeError:
576 pass
577 else:
578 self.fail("exec should have failed, because code contained free vars")
580 def testListCompLocalVars(self):
582 try:
583 print bad
584 except NameError:
585 pass
586 else:
587 print "bad should not be defined"
589 def x():
590 [bad for s in 'a b' for bad in s.split()]
593 try:
594 print bad
595 except NameError:
596 pass
598 def testEvalFreeVars(self):
600 def f(x):
601 def g():
603 eval("x + 1")
604 return g
606 f(4)()
608 def testFreeingCell(self):
609 # Test what happens when a finalizer accesses
610 # the cell where the object was stored.
611 class Special:
612 def __del__(self):
613 nestedcell_get()
615 def f():
616 global nestedcell_get
617 def nestedcell_get():
618 return c
620 c = (Special(),)
621 c = 2
623 f() # used to crash the interpreter...
625 def testGlobalInParallelNestedFunctions(self):
626 # A symbol table bug leaked the global statement from one
627 # function to other nested functions in the same block.
628 # This test verifies that a global statement in the first
629 # function does not affect the second function.
630 CODE = """def f():
631 y = 1
632 def g():
633 global y
634 return y
635 def h():
636 return y + 1
637 return g, h
639 y = 9
640 g, h = f()
641 result9 = g()
642 result2 = h()
644 local_ns = {}
645 global_ns = {}
646 exec CODE in local_ns, global_ns
647 self.assertEqual(2, global_ns["result2"])
648 self.assertEqual(9, global_ns["result9"])
651 def test_main():
652 with check_warnings(("import \* only allowed at module level",
653 SyntaxWarning)):
654 run_unittest(ScopeTests)
656 if __name__ == '__main__':
657 test_main()