• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import unittest
2from test.test_support import check_syntax_error, check_py3k_warnings, \
3                              check_warnings, run_unittest
4
5
6class ScopeTests(unittest.TestCase):
7
8    def testSimpleNesting(self):
9
10        def make_adder(x):
11            def adder(y):
12                return x + y
13            return adder
14
15        inc = make_adder(1)
16        plus10 = make_adder(10)
17
18        self.assertEqual(inc(1), 2)
19        self.assertEqual(plus10(-2), 8)
20
21    def testExtraNesting(self):
22
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()
29
30        inc = make_adder2(1)
31        plus10 = make_adder2(10)
32
33        self.assertEqual(inc(1), 2)
34        self.assertEqual(plus10(-2), 8)
35
36    def testSimpleAndRebinding(self):
37
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
43
44        inc = make_adder3(0)
45        plus10 = make_adder3(9)
46
47        self.assertEqual(inc(1), 2)
48        self.assertEqual(plus10(-2), 8)
49
50    def testNestingGlobalNoFree(self):
51
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()
60
61        global_x = 1
62        adder = make_adder4()
63        self.assertEqual(adder(1), 2)
64
65        global_x = 10
66        self.assertEqual(adder(-2), 8)
67
68    def testNestingThroughClass(self):
69
70        def make_adder5(x):
71            class Adder:
72                def __call__(self, y):
73                    return x + y
74            return Adder()
75
76        inc = make_adder5(1)
77        plus10 = make_adder5(10)
78
79        self.assertEqual(inc(1), 2)
80        self.assertEqual(plus10(-2), 8)
81
82    def testNestingPlusFreeRefToGlobal(self):
83
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
90
91        inc = make_adder6(1)
92        plus10 = make_adder6(10)
93
94        self.assertEqual(inc(1), 11) # there's only one global
95        self.assertEqual(plus10(-2), 8)
96
97    def testNearestEnclosingScope(self):
98
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)
106
107        test_func = f(10)
108        self.assertEqual(test_func(5), 47)
109
110    def testMixedFreevarsAndCellvars(self):
111
112        def identity(x):
113            return x
114
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
125
126        g = f(1, 2, 3)
127        h = g(2, 4, 6)
128        self.assertEqual(h(), 39)
129
130    def testFreeVarInMethod(self):
131
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()
144
145        t = test()
146        self.assertEqual(t.test(), "var")
147        self.assertEqual(t.method_and_var(), "method")
148        self.assertEqual(t.actual_global(), "global")
149
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)
161
162        t = Test()
163        self.assertEqual(t.test(), "var")
164        self.assertEqual(t.method_and_var(), "method")
165        self.assertEqual(t.actual_global(), "global")
166
167    def testRecursion(self):
168
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"
179
180        self.assertEqual(f(6), 720)
181
182
183    def testUnoptimizedNamespaces(self):
184
185        check_syntax_error(self, """\
186def unoptimized_clash1(strip):
187    def f(s):
188        from string import *
189        return strip(s) # ambiguity: free or local
190    return f
191""")
192
193        check_syntax_error(self, """\
194def unoptimized_clash2():
195    from string import *
196    def f(s):
197        return strip(s) # ambiguity: global or local
198    return f
199""")
200
201        check_syntax_error(self, """\
202def 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""")
209
210        # XXX could allow this for exec with const argument, but what's the point
211        check_syntax_error(self, """\
212def error(y):
213    exec "a = 1"
214    def f(x):
215        return x + y
216    return f
217""")
218
219        check_syntax_error(self, """\
220def f(x):
221    def g():
222        return x
223    del x # can't del name
224""")
225
226        check_syntax_error(self, """\
227def f():
228    def g():
229        from string import *
230        return strip # global or local?
231""")
232
233        # and verify a few cases that should work
234
235        exec """
236def noproblem1():
237    from string import *
238    f = lambda x:x
239
240def noproblem2():
241    from string import *
242    def f(x):
243        return x + 1
244
245def noproblem3():
246    from string import *
247    def f(x):
248        global y
249        y = x
250"""
251
252    def testLambdas(self):
253
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)
259
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)
265
266        f3 = lambda x: lambda y: global_x + y
267        global_x = 1
268        inc = f3(None)
269        self.assertEqual(inc(2), 3)
270
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)
275
276    def testUnboundLocal(self):
277
278        def errorInOuter():
279            print y
280            def inner():
281                return y
282            y = 1
283
284        def errorInInner():
285            def inner():
286                return y
287            inner()
288            y = 1
289
290        self.assertRaises(UnboundLocalError, errorInOuter)
291        self.assertRaises(NameError, errorInInner)
292
293        # test for bug #1501934: incorrect LOAD/STORE_GLOBAL generation
294        exec """
295global_x = 1
296def f():
297    global_x += 1
298try:
299    f()
300except UnboundLocalError:
301    pass
302else:
303    fail('scope of global_x not correctly determined')
304""" in {'fail': self.fail}
305
306    def testComplexDefinitions(self):
307
308        def makeReturner(*lst):
309            def returner():
310                return lst
311            return returner
312
313        self.assertEqual(makeReturner(1,2,3)(), (1,2,3))
314
315        def makeReturner2(**kwargs):
316            def returner():
317                return kwargs
318            return returner
319
320        self.assertEqual(makeReturner2(a=11)()['a'], 11)
321
322        with check_py3k_warnings(("tuple parameter unpacking has been removed",
323                                  SyntaxWarning)):
324            exec """\
325def 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))
331
332    def testScopeOfGlobalStmt(self):
333# Examples posted by Samuele Pedroni to python-dev on 3/1/2001
334
335        exec """\
336# I
337x = 7
338def 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()
348self.assertEqual(f(), 7)
349self.assertEqual(x, 7)
350
351# II
352x = 7
353def 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()
363self.assertEqual(f(), 2)
364self.assertEqual(x, 7)
365
366# III
367x = 7
368def 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()
379self.assertEqual(f(), 2)
380self.assertEqual(x, 2)
381
382# IV
383x = 7
384def 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()
395self.assertEqual(f(), 2)
396self.assertEqual(x, 2)
397
398# XXX what about global statements in class blocks?
399# do they affect methods?
400
401x = 12
402class Global:
403    global x
404    x = 13
405    def set(self, val):
406        x = val
407    def get(self):
408        return x
409
410g = Global()
411self.assertEqual(g.get(), 13)
412g.set(15)
413self.assertEqual(g.get(), 13)
414"""
415
416    def testLeaks(self):
417
418        class Foo:
419            count = 0
420
421            def __init__(self):
422                Foo.count += 1
423
424            def __del__(self):
425                Foo.count -= 1
426
427        def f1():
428            x = Foo()
429            def f2():
430                return x
431            f2()
432
433        for i in range(100):
434            f1()
435
436        self.assertEqual(Foo.count, 0)
437
438    def testClassAndGlobal(self):
439
440        exec """\
441def test(x):
442    class Foo:
443        global x
444        def __call__(self, y):
445            return x + y
446    return Foo()
447
448x = 0
449self.assertEqual(test(6)(2), 8)
450x = -1
451self.assertEqual(test(3)(2), 5)
452
453looked_up_by_load_name = False
454class 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
459
460self.assertTrue(X.passed)
461"""
462
463    def testLocalsFunction(self):
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        self.assertIn('h', d)
476        del d['h']
477        self.assertEqual(d, {'x': 2, 'y': 7, 'w': 6})
478
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.
485        #
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.
489
490        def f(x):
491            class C:
492                x = 12
493                def m(self):
494                    return x
495                locals()
496            return C
497
498        self.assertEqual(f(1).x, 12)
499
500        def f(x):
501            class C:
502                y = x
503                def m(self):
504                    return x
505                z = list(locals())
506            return C
507
508        varnames = f(1).z
509        self.assertNotIn("x", varnames)
510        self.assertIn("y", varnames)
511
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
521
522            class C:
523                def f(self):
524                    return x
525
526            self.assertEqual(x, 12) # Used to raise UnboundLocalError
527        finally:
528            sys.settrace(None)
529
530    def testBoundAndFree(self):
531        # var is bound and free in class
532
533        def f(x):
534            class C:
535                def m(self):
536                    return x
537                a = x
538            return C
539
540        inst = f(3)()
541        self.assertEqual(inst.a, inst.m())
542
543    def testInteractionWithTraceFunc(self):
544
545        import sys
546        def tracer(a,b,c):
547            return tracer
548
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)
555
556        class TestClass:
557            pass
558
559        sys.settrace(tracer)
560        adaptgetter("foo", TestClass, (1, ""))
561        sys.settrace(None)
562
563        self.assertRaises(TypeError, sys.settrace)
564
565    def testEvalExecFreeVars(self):
566
567        def f(x):
568            return lambda: x + 1
569
570        g = f(3)
571        self.assertRaises(TypeError, eval, g.func_code)
572
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")
579
580    def testListCompLocalVars(self):
581
582        try:
583            print bad
584        except NameError:
585            pass
586        else:
587            print "bad should not be defined"
588
589        def x():
590            [bad for s in 'a b' for bad in s.split()]
591
592        x()
593        try:
594            print bad
595        except NameError:
596            pass
597
598    def testEvalFreeVars(self):
599
600        def f(x):
601            def g():
602                x
603                eval("x + 1")
604            return g
605
606        f(4)()
607
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()
614
615        def f():
616            global nestedcell_get
617            def nestedcell_get():
618                return c
619
620            c = (Special(),)
621            c = 2
622
623        f() # used to crash the interpreter...
624
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
638
639y = 9
640g, h = f()
641result9 = g()
642result2 = h()
643"""
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"])
649
650    def testTopIsNotSignificant(self):
651        # See #9997.
652        def top(a):
653            pass
654        def b():
655            global a
656
657
658def test_main():
659    with check_warnings(("import \* only allowed at module level",
660                         SyntaxWarning)):
661        run_unittest(ScopeTests)
662
663if __name__ == '__main__':
664    test_main()
665