test_scope.py revision 2943cdb5eb7f342a4cdaec59893825de172eedc6
1import gc
2import unittest
3import weakref
4
5from test.support import check_syntax_error, cpython_only, run_unittest
6
7
8class ScopeTests(unittest.TestCase):
9
10    def testSimpleNesting(self):
11
12        def make_adder(x):
13            def adder(y):
14                return x + y
15            return adder
16
17        inc = make_adder(1)
18        plus10 = make_adder(10)
19
20        self.assertEqual(inc(1), 2)
21        self.assertEqual(plus10(-2), 8)
22
23    def testExtraNesting(self):
24
25        def make_adder2(x):
26            def extra(): # check freevars passing through non-use scopes
27                def adder(y):
28                    return x + y
29                return adder
30            return extra()
31
32        inc = make_adder2(1)
33        plus10 = make_adder2(10)
34
35        self.assertEqual(inc(1), 2)
36        self.assertEqual(plus10(-2), 8)
37
38    def testSimpleAndRebinding(self):
39
40        def make_adder3(x):
41            def adder(y):
42                return x + y
43            x = x + 1 # check tracking of assignment to x in defining scope
44            return adder
45
46        inc = make_adder3(0)
47        plus10 = make_adder3(9)
48
49        self.assertEqual(inc(1), 2)
50        self.assertEqual(plus10(-2), 8)
51
52    def testNestingGlobalNoFree(self):
53
54        def make_adder4(): # XXX add exta level of indirection
55            def nest():
56                def nest():
57                    def adder(y):
58                        return global_x + y # check that plain old globals work
59                    return adder
60                return nest()
61            return nest()
62
63        global_x = 1
64        adder = make_adder4()
65        self.assertEqual(adder(1), 2)
66
67        global_x = 10
68        self.assertEqual(adder(-2), 8)
69
70    def testNestingThroughClass(self):
71
72        def make_adder5(x):
73            class Adder:
74                def __call__(self, y):
75                    return x + y
76            return Adder()
77
78        inc = make_adder5(1)
79        plus10 = make_adder5(10)
80
81        self.assertEqual(inc(1), 2)
82        self.assertEqual(plus10(-2), 8)
83
84    def testNestingPlusFreeRefToGlobal(self):
85
86        def make_adder6(x):
87            global global_nest_x
88            def adder(y):
89                return global_nest_x + y
90            global_nest_x = x
91            return adder
92
93        inc = make_adder6(1)
94        plus10 = make_adder6(10)
95
96        self.assertEqual(inc(1), 11) # there's only one global
97        self.assertEqual(plus10(-2), 8)
98
99    def testNearestEnclosingScope(self):
100
101        def f(x):
102            def g(y):
103                x = 42 # check that this masks binding in f()
104                def h(z):
105                    return x + z
106                return h
107            return g(2)
108
109        test_func = f(10)
110        self.assertEqual(test_func(5), 47)
111
112    def testMixedFreevarsAndCellvars(self):
113
114        def identity(x):
115            return x
116
117        def f(x, y, z):
118            def g(a, b, c):
119                a = a + x # 3
120                def h():
121                    # z * (4 + 9)
122                    # 3 * 13
123                    return identity(z * (b + y))
124                y = c + z # 9
125                return h
126            return g
127
128        g = f(1, 2, 3)
129        h = g(2, 4, 6)
130        self.assertEqual(h(), 39)
131
132    def testFreeVarInMethod(self):
133
134        def test():
135            method_and_var = "var"
136            class Test:
137                def method_and_var(self):
138                    return "method"
139                def test(self):
140                    return method_and_var
141                def actual_global(self):
142                    return str("global")
143                def str(self):
144                    return str(self)
145            return Test()
146
147        t = test()
148        self.assertEqual(t.test(), "var")
149        self.assertEqual(t.method_and_var(), "method")
150        self.assertEqual(t.actual_global(), "global")
151
152        method_and_var = "var"
153        class Test:
154            # this class is not nested, so the rules are different
155            def method_and_var(self):
156                return "method"
157            def test(self):
158                return method_and_var
159            def actual_global(self):
160                return str("global")
161            def str(self):
162                return str(self)
163
164        t = Test()
165        self.assertEqual(t.test(), "var")
166        self.assertEqual(t.method_and_var(), "method")
167        self.assertEqual(t.actual_global(), "global")
168
169    def testCellIsKwonlyArg(self):
170        # Issue 1409: Initialisation of a cell value,
171        # when it comes from a keyword-only parameter
172        def foo(*, a=17):
173            def bar():
174                return a + 5
175            return bar() + 3
176
177        self.assertEqual(foo(a=42), 50)
178        self.assertEqual(foo(), 25)
179
180    def testRecursion(self):
181
182        def f(x):
183            def fact(n):
184                if n == 0:
185                    return 1
186                else:
187                    return n * fact(n - 1)
188            if x >= 0:
189                return fact(x)
190            else:
191                raise ValueError("x must be >= 0")
192
193        self.assertEqual(f(6), 720)
194
195
196    def testUnoptimizedNamespaces(self):
197
198        check_syntax_error(self, """if 1:
199            def unoptimized_clash1(strip):
200                def f(s):
201                    from sys import *
202                    return getrefcount(s) # ambiguity: free or local
203                return f
204            """)
205
206        check_syntax_error(self, """if 1:
207            def unoptimized_clash2():
208                from sys import *
209                def f(s):
210                    return getrefcount(s) # ambiguity: global or local
211                return f
212            """)
213
214        check_syntax_error(self, """if 1:
215            def unoptimized_clash2():
216                from sys import *
217                def g():
218                    def f(s):
219                        return getrefcount(s) # ambiguity: global or local
220                    return f
221            """)
222
223        check_syntax_error(self, """if 1:
224            def f():
225                def g():
226                    from sys import *
227                    return getrefcount # global or local?
228            """)
229
230    def testLambdas(self):
231
232        f1 = lambda x: lambda y: x + y
233        inc = f1(1)
234        plus10 = f1(10)
235        self.assertEqual(inc(1), 2)
236        self.assertEqual(plus10(5), 15)
237
238        f2 = lambda x: (lambda : lambda y: x + y)()
239        inc = f2(1)
240        plus10 = f2(10)
241        self.assertEqual(inc(1), 2)
242        self.assertEqual(plus10(5), 15)
243
244        f3 = lambda x: lambda y: global_x + y
245        global_x = 1
246        inc = f3(None)
247        self.assertEqual(inc(2), 3)
248
249        f8 = lambda x, y, z: lambda a, b, c: lambda : z * (b + y)
250        g = f8(1, 2, 3)
251        h = g(2, 4, 6)
252        self.assertEqual(h(), 18)
253
254    def testUnboundLocal(self):
255
256        def errorInOuter():
257            print(y)
258            def inner():
259                return y
260            y = 1
261
262        def errorInInner():
263            def inner():
264                return y
265            inner()
266            y = 1
267
268        self.assertRaises(UnboundLocalError, errorInOuter)
269        self.assertRaises(NameError, errorInInner)
270
271    def testUnboundLocal_AfterDel(self):
272        # #4617: It is now legal to delete a cell variable.
273        # The following functions must obviously compile,
274        # and give the correct error when accessing the deleted name.
275        def errorInOuter():
276            y = 1
277            del y
278            print(y)
279            def inner():
280                return y
281
282        def errorInInner():
283            def inner():
284                return y
285            y = 1
286            del y
287            inner()
288
289        self.assertRaises(UnboundLocalError, errorInOuter)
290        self.assertRaises(NameError, errorInInner)
291
292    def testUnboundLocal_AugAssign(self):
293        # test for bug #1501934: incorrect LOAD/STORE_GLOBAL generation
294        exec("""if 1:
295            global_x = 1
296            def f():
297                global_x += 1
298            try:
299                f()
300            except UnboundLocalError:
301                pass
302            else:
303                fail('scope of global_x not correctly determined')
304            """, {'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    def testScopeOfGlobalStmt(self):
323        # Examples posted by Samuele Pedroni to python-dev on 3/1/2001
324
325        exec("""if 1:
326            # I
327            x = 7
328            def f():
329                x = 1
330                def g():
331                    global x
332                    def i():
333                        def h():
334                            return x
335                        return h()
336                    return i()
337                return g()
338            self.assertEqual(f(), 7)
339            self.assertEqual(x, 7)
340
341            # II
342            x = 7
343            def f():
344                x = 1
345                def g():
346                    x = 2
347                    def i():
348                        def h():
349                            return x
350                        return h()
351                    return i()
352                return g()
353            self.assertEqual(f(), 2)
354            self.assertEqual(x, 7)
355
356            # III
357            x = 7
358            def f():
359                x = 1
360                def g():
361                    global x
362                    x = 2
363                    def i():
364                        def h():
365                            return x
366                        return h()
367                    return i()
368                return g()
369            self.assertEqual(f(), 2)
370            self.assertEqual(x, 2)
371
372            # IV
373            x = 7
374            def f():
375                x = 3
376                def g():
377                    global x
378                    x = 2
379                    def i():
380                        def h():
381                            return x
382                        return h()
383                    return i()
384                return g()
385            self.assertEqual(f(), 2)
386            self.assertEqual(x, 2)
387
388            # XXX what about global statements in class blocks?
389            # do they affect methods?
390
391            x = 12
392            class Global:
393                global x
394                x = 13
395                def set(self, val):
396                    x = val
397                def get(self):
398                    return x
399
400            g = Global()
401            self.assertEqual(g.get(), 13)
402            g.set(15)
403            self.assertEqual(g.get(), 13)
404            """)
405
406    def testLeaks(self):
407
408        class Foo:
409            count = 0
410
411            def __init__(self):
412                Foo.count += 1
413
414            def __del__(self):
415                Foo.count -= 1
416
417        def f1():
418            x = Foo()
419            def f2():
420                return x
421            f2()
422
423        for i in range(100):
424            f1()
425
426        self.assertEqual(Foo.count, 0)
427
428    def testClassAndGlobal(self):
429
430        exec("""if 1:
431            def test(x):
432                class Foo:
433                    global x
434                    def __call__(self, y):
435                        return x + y
436                return Foo()
437
438            x = 0
439            self.assertEqual(test(6)(2), 8)
440            x = -1
441            self.assertEqual(test(3)(2), 5)
442
443            looked_up_by_load_name = False
444            class X:
445                # Implicit globals inside classes are be looked up by LOAD_NAME, not
446                # LOAD_GLOBAL.
447                locals()['looked_up_by_load_name'] = True
448                passed = looked_up_by_load_name
449
450            self.assertTrue(X.passed)
451            """)
452
453    def testLocalsFunction(self):
454
455        def f(x):
456            def g(y):
457                def h(z):
458                    return y + z
459                w = x + y
460                y += 3
461                return locals()
462            return g
463
464        d = f(2)(4)
465        self.assertIn('h', d)
466        del d['h']
467        self.assertEqual(d, {'x': 2, 'y': 7, 'w': 6})
468
469    def testLocalsClass(self):
470        # This test verifies that calling locals() does not pollute
471        # the local namespace of the class with free variables.  Old
472        # versions of Python had a bug, where a free variable being
473        # passed through a class namespace would be inserted into
474        # locals() by locals() or exec or a trace function.
475        #
476        # The real bug lies in frame code that copies variables
477        # between fast locals and the locals dict, e.g. when executing
478        # a trace function.
479
480        def f(x):
481            class C:
482                x = 12
483                def m(self):
484                    return x
485                locals()
486            return C
487
488        self.assertEqual(f(1).x, 12)
489
490        def f(x):
491            class C:
492                y = x
493                def m(self):
494                    return x
495                z = list(locals())
496            return C
497
498        varnames = f(1).z
499        self.assertNotIn("x", varnames)
500        self.assertIn("y", varnames)
501
502    @cpython_only
503    def testLocalsClass_WithTrace(self):
504        # Issue23728: after the trace function returns, the locals()
505        # dictionary is used to update all variables, this used to
506        # include free variables. But in class statements, free
507        # variables are not inserted...
508        import sys
509        self.addCleanup(sys.settrace, sys.gettrace())
510        sys.settrace(lambda a,b,c:None)
511        x = 12
512
513        class C:
514            def f(self):
515                return x
516
517        self.assertEqual(x, 12) # Used to raise UnboundLocalError
518
519    def testBoundAndFree(self):
520        # var is bound and free in class
521
522        def f(x):
523            class C:
524                def m(self):
525                    return x
526                a = x
527            return C
528
529        inst = f(3)()
530        self.assertEqual(inst.a, inst.m())
531
532    @cpython_only
533    def testInteractionWithTraceFunc(self):
534
535        import sys
536        def tracer(a,b,c):
537            return tracer
538
539        def adaptgetter(name, klass, getter):
540            kind, des = getter
541            if kind == 1:       # AV happens when stepping from this line to next
542                if des == "":
543                    des = "_%s__%s" % (klass.__name__, name)
544                return lambda obj: getattr(obj, des)
545
546        class TestClass:
547            pass
548
549        self.addCleanup(sys.settrace, sys.gettrace())
550        sys.settrace(tracer)
551        adaptgetter("foo", TestClass, (1, ""))
552        sys.settrace(None)
553
554        self.assertRaises(TypeError, sys.settrace)
555
556    def testEvalExecFreeVars(self):
557
558        def f(x):
559            return lambda: x + 1
560
561        g = f(3)
562        self.assertRaises(TypeError, eval, g.__code__)
563
564        try:
565            exec(g.__code__, {})
566        except TypeError:
567            pass
568        else:
569            self.fail("exec should have failed, because code contained free vars")
570
571    def testListCompLocalVars(self):
572
573        try:
574            print(bad)
575        except NameError:
576            pass
577        else:
578            print("bad should not be defined")
579
580        def x():
581            [bad for s in 'a b' for bad in s.split()]
582
583        x()
584        try:
585            print(bad)
586        except NameError:
587            pass
588
589    def testEvalFreeVars(self):
590
591        def f(x):
592            def g():
593                x
594                eval("x + 1")
595            return g
596
597        f(4)()
598
599    def testFreeingCell(self):
600        # Test what happens when a finalizer accesses
601        # the cell where the object was stored.
602        class Special:
603            def __del__(self):
604                nestedcell_get()
605
606    def testNonLocalFunction(self):
607
608        def f(x):
609            def inc():
610                nonlocal x
611                x += 1
612                return x
613            def dec():
614                nonlocal x
615                x -= 1
616                return x
617            return inc, dec
618
619        inc, dec = f(0)
620        self.assertEqual(inc(), 1)
621        self.assertEqual(inc(), 2)
622        self.assertEqual(dec(), 1)
623        self.assertEqual(dec(), 0)
624
625    def testNonLocalMethod(self):
626        def f(x):
627            class c:
628                def inc(self):
629                    nonlocal x
630                    x += 1
631                    return x
632                def dec(self):
633                    nonlocal x
634                    x -= 1
635                    return x
636            return c()
637        c = f(0)
638        self.assertEqual(c.inc(), 1)
639        self.assertEqual(c.inc(), 2)
640        self.assertEqual(c.dec(), 1)
641        self.assertEqual(c.dec(), 0)
642
643    def testGlobalInParallelNestedFunctions(self):
644        # A symbol table bug leaked the global statement from one
645        # function to other nested functions in the same block.
646        # This test verifies that a global statement in the first
647        # function does not affect the second function.
648        local_ns = {}
649        global_ns = {}
650        exec("""if 1:
651            def f():
652                y = 1
653                def g():
654                    global y
655                    return y
656                def h():
657                    return y + 1
658                return g, h
659            y = 9
660            g, h = f()
661            result9 = g()
662            result2 = h()
663            """, local_ns, global_ns)
664        self.assertEqual(2, global_ns["result2"])
665        self.assertEqual(9, global_ns["result9"])
666
667    def testNonLocalClass(self):
668
669        def f(x):
670            class c:
671                nonlocal x
672                x += 1
673                def get(self):
674                    return x
675            return c()
676
677        c = f(0)
678        self.assertEqual(c.get(), 1)
679        self.assertNotIn("x", c.__class__.__dict__)
680
681
682    def testNonLocalGenerator(self):
683
684        def f(x):
685            def g(y):
686                nonlocal x
687                for i in range(y):
688                    x += 1
689                    yield x
690            return g
691
692        g = f(0)
693        self.assertEqual(list(g(5)), [1, 2, 3, 4, 5])
694
695    def testNestedNonLocal(self):
696
697        def f(x):
698            def g():
699                nonlocal x
700                x -= 2
701                def h():
702                    nonlocal x
703                    x += 4
704                    return x
705                return h
706            return g
707
708        g = f(1)
709        h = g()
710        self.assertEqual(h(), 3)
711
712    def testTopIsNotSignificant(self):
713        # See #9997.
714        def top(a):
715            pass
716        def b():
717            global a
718
719    def testClassNamespaceOverridesClosure(self):
720        # See #17853.
721        x = 42
722        class X:
723            locals()["x"] = 43
724            y = x
725        self.assertEqual(X.y, 43)
726        class X:
727            locals()["x"] = 43
728            del x
729        self.assertFalse(hasattr(X, "x"))
730        self.assertEqual(x, 42)
731
732    @cpython_only
733    def testCellLeak(self):
734        # Issue 17927.
735        #
736        # The issue was that if self was part of a cycle involving the
737        # frame of a method call, *and* the method contained a nested
738        # function referencing self, thereby forcing 'self' into a
739        # cell, setting self to None would not be enough to break the
740        # frame -- the frame had another reference to the instance,
741        # which could not be cleared by the code running in the frame
742        # (though it will be cleared when the frame is collected).
743        # Without the lambda, setting self to None is enough to break
744        # the cycle.
745        class Tester:
746            def dig(self):
747                if 0:
748                    lambda: self
749                try:
750                    1/0
751                except Exception as exc:
752                    self.exc = exc
753                self = None  # Break the cycle
754        tester = Tester()
755        tester.dig()
756        ref = weakref.ref(tester)
757        del tester
758        self.assertIsNone(ref())
759
760
761def test_main():
762    run_unittest(ScopeTests)
763
764if __name__ == '__main__':
765    test_main()
766