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