1import unittest
2import weakref
3
4from test.support import check_syntax_error, cpython_only
5from test.support import gc_collect
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 testCellIsArgAndEscapes(self):
181        # We need to be sure that a cell passed in as an arg still
182        # gets wrapped in a new cell if the arg escapes into an
183        # inner function (closure).
184
185        def external():
186            value = 42
187            def inner():
188                return value
189            cell, = inner.__closure__
190            return cell
191        cell_ext = external()
192
193        def spam(arg):
194            def eggs():
195                return arg
196            return eggs
197
198        eggs = spam(cell_ext)
199        cell_closure, = eggs.__closure__
200        cell_eggs = eggs()
201
202        self.assertIs(cell_eggs, cell_ext)
203        self.assertIsNot(cell_eggs, cell_closure)
204
205    def testCellIsLocalAndEscapes(self):
206        # We need to be sure that a cell bound to a local still
207        # gets wrapped in a new cell if the local escapes into an
208        # inner function (closure).
209
210        def external():
211            value = 42
212            def inner():
213                return value
214            cell, = inner.__closure__
215            return cell
216        cell_ext = external()
217
218        def spam(arg):
219            cell = arg
220            def eggs():
221                return cell
222            return eggs
223
224        eggs = spam(cell_ext)
225        cell_closure, = eggs.__closure__
226        cell_eggs = eggs()
227
228        self.assertIs(cell_eggs, cell_ext)
229        self.assertIsNot(cell_eggs, cell_closure)
230
231    def testRecursion(self):
232
233        def f(x):
234            def fact(n):
235                if n == 0:
236                    return 1
237                else:
238                    return n * fact(n - 1)
239            if x >= 0:
240                return fact(x)
241            else:
242                raise ValueError("x must be >= 0")
243
244        self.assertEqual(f(6), 720)
245
246
247    def testUnoptimizedNamespaces(self):
248
249        check_syntax_error(self, """if 1:
250            def unoptimized_clash1(strip):
251                def f(s):
252                    from sys import *
253                    return getrefcount(s) # ambiguity: free or local
254                return f
255            """)
256
257        check_syntax_error(self, """if 1:
258            def unoptimized_clash2():
259                from sys import *
260                def f(s):
261                    return getrefcount(s) # ambiguity: global or local
262                return f
263            """)
264
265        check_syntax_error(self, """if 1:
266            def unoptimized_clash2():
267                from sys import *
268                def g():
269                    def f(s):
270                        return getrefcount(s) # ambiguity: global or local
271                    return f
272            """)
273
274        check_syntax_error(self, """if 1:
275            def f():
276                def g():
277                    from sys import *
278                    return getrefcount # global or local?
279            """)
280
281    def testLambdas(self):
282
283        f1 = lambda x: lambda y: x + y
284        inc = f1(1)
285        plus10 = f1(10)
286        self.assertEqual(inc(1), 2)
287        self.assertEqual(plus10(5), 15)
288
289        f2 = lambda x: (lambda : lambda y: x + y)()
290        inc = f2(1)
291        plus10 = f2(10)
292        self.assertEqual(inc(1), 2)
293        self.assertEqual(plus10(5), 15)
294
295        f3 = lambda x: lambda y: global_x + y
296        global_x = 1
297        inc = f3(None)
298        self.assertEqual(inc(2), 3)
299
300        f8 = lambda x, y, z: lambda a, b, c: lambda : z * (b + y)
301        g = f8(1, 2, 3)
302        h = g(2, 4, 6)
303        self.assertEqual(h(), 18)
304
305    def testUnboundLocal(self):
306
307        def errorInOuter():
308            print(y)
309            def inner():
310                return y
311            y = 1
312
313        def errorInInner():
314            def inner():
315                return y
316            inner()
317            y = 1
318
319        self.assertRaises(UnboundLocalError, errorInOuter)
320        self.assertRaises(NameError, errorInInner)
321
322    def testUnboundLocal_AfterDel(self):
323        # #4617: It is now legal to delete a cell variable.
324        # The following functions must obviously compile,
325        # and give the correct error when accessing the deleted name.
326        def errorInOuter():
327            y = 1
328            del y
329            print(y)
330            def inner():
331                return y
332
333        def errorInInner():
334            def inner():
335                return y
336            y = 1
337            del y
338            inner()
339
340        self.assertRaises(UnboundLocalError, errorInOuter)
341        self.assertRaises(NameError, errorInInner)
342
343    def testUnboundLocal_AugAssign(self):
344        # test for bug #1501934: incorrect LOAD/STORE_GLOBAL generation
345        exec("""if 1:
346            global_x = 1
347            def f():
348                global_x += 1
349            try:
350                f()
351            except UnboundLocalError:
352                pass
353            else:
354                fail('scope of global_x not correctly determined')
355            """, {'fail': self.fail})
356
357    def testComplexDefinitions(self):
358
359        def makeReturner(*lst):
360            def returner():
361                return lst
362            return returner
363
364        self.assertEqual(makeReturner(1,2,3)(), (1,2,3))
365
366        def makeReturner2(**kwargs):
367            def returner():
368                return kwargs
369            return returner
370
371        self.assertEqual(makeReturner2(a=11)()['a'], 11)
372
373    def testScopeOfGlobalStmt(self):
374        # Examples posted by Samuele Pedroni to python-dev on 3/1/2001
375
376        exec("""if 1:
377            # I
378            x = 7
379            def f():
380                x = 1
381                def g():
382                    global x
383                    def i():
384                        def h():
385                            return x
386                        return h()
387                    return i()
388                return g()
389            self.assertEqual(f(), 7)
390            self.assertEqual(x, 7)
391
392            # II
393            x = 7
394            def f():
395                x = 1
396                def g():
397                    x = 2
398                    def i():
399                        def h():
400                            return x
401                        return h()
402                    return i()
403                return g()
404            self.assertEqual(f(), 2)
405            self.assertEqual(x, 7)
406
407            # III
408            x = 7
409            def f():
410                x = 1
411                def g():
412                    global x
413                    x = 2
414                    def i():
415                        def h():
416                            return x
417                        return h()
418                    return i()
419                return g()
420            self.assertEqual(f(), 2)
421            self.assertEqual(x, 2)
422
423            # IV
424            x = 7
425            def f():
426                x = 3
427                def g():
428                    global x
429                    x = 2
430                    def i():
431                        def h():
432                            return x
433                        return h()
434                    return i()
435                return g()
436            self.assertEqual(f(), 2)
437            self.assertEqual(x, 2)
438
439            # XXX what about global statements in class blocks?
440            # do they affect methods?
441
442            x = 12
443            class Global:
444                global x
445                x = 13
446                def set(self, val):
447                    x = val
448                def get(self):
449                    return x
450
451            g = Global()
452            self.assertEqual(g.get(), 13)
453            g.set(15)
454            self.assertEqual(g.get(), 13)
455            """)
456
457    def testLeaks(self):
458
459        class Foo:
460            count = 0
461
462            def __init__(self):
463                Foo.count += 1
464
465            def __del__(self):
466                Foo.count -= 1
467
468        def f1():
469            x = Foo()
470            def f2():
471                return x
472            f2()
473
474        for i in range(100):
475            f1()
476
477        gc_collect()  # For PyPy or other GCs.
478        self.assertEqual(Foo.count, 0)
479
480    def testClassAndGlobal(self):
481
482        exec("""if 1:
483            def test(x):
484                class Foo:
485                    global x
486                    def __call__(self, y):
487                        return x + y
488                return Foo()
489
490            x = 0
491            self.assertEqual(test(6)(2), 8)
492            x = -1
493            self.assertEqual(test(3)(2), 5)
494
495            looked_up_by_load_name = False
496            class X:
497                # Implicit globals inside classes are be looked up by LOAD_NAME, not
498                # LOAD_GLOBAL.
499                locals()['looked_up_by_load_name'] = True
500                passed = looked_up_by_load_name
501
502            self.assertTrue(X.passed)
503            """)
504
505    def testLocalsFunction(self):
506
507        def f(x):
508            def g(y):
509                def h(z):
510                    return y + z
511                w = x + y
512                y += 3
513                return locals()
514            return g
515
516        d = f(2)(4)
517        self.assertIn('h', d)
518        del d['h']
519        self.assertEqual(d, {'x': 2, 'y': 7, 'w': 6})
520
521    def testLocalsClass(self):
522        # This test verifies that calling locals() does not pollute
523        # the local namespace of the class with free variables.  Old
524        # versions of Python had a bug, where a free variable being
525        # passed through a class namespace would be inserted into
526        # locals() by locals() or exec or a trace function.
527        #
528        # The real bug lies in frame code that copies variables
529        # between fast locals and the locals dict, e.g. when executing
530        # a trace function.
531
532        def f(x):
533            class C:
534                x = 12
535                def m(self):
536                    return x
537                locals()
538            return C
539
540        self.assertEqual(f(1).x, 12)
541
542        def f(x):
543            class C:
544                y = x
545                def m(self):
546                    return x
547                z = list(locals())
548            return C
549
550        varnames = f(1).z
551        self.assertNotIn("x", varnames)
552        self.assertIn("y", varnames)
553
554    @cpython_only
555    def testLocalsClass_WithTrace(self):
556        # Issue23728: after the trace function returns, the locals()
557        # dictionary is used to update all variables, this used to
558        # include free variables. But in class statements, free
559        # variables are not inserted...
560        import sys
561        self.addCleanup(sys.settrace, sys.gettrace())
562        sys.settrace(lambda a,b,c:None)
563        x = 12
564
565        class C:
566            def f(self):
567                return x
568
569        self.assertEqual(x, 12) # Used to raise UnboundLocalError
570
571    def testBoundAndFree(self):
572        # var is bound and free in class
573
574        def f(x):
575            class C:
576                def m(self):
577                    return x
578                a = x
579            return C
580
581        inst = f(3)()
582        self.assertEqual(inst.a, inst.m())
583
584    @cpython_only
585    def testInteractionWithTraceFunc(self):
586
587        import sys
588        def tracer(a,b,c):
589            return tracer
590
591        def adaptgetter(name, klass, getter):
592            kind, des = getter
593            if kind == 1:       # AV happens when stepping from this line to next
594                if des == "":
595                    des = "_%s__%s" % (klass.__name__, name)
596                return lambda obj: getattr(obj, des)
597
598        class TestClass:
599            pass
600
601        self.addCleanup(sys.settrace, sys.gettrace())
602        sys.settrace(tracer)
603        adaptgetter("foo", TestClass, (1, ""))
604        sys.settrace(None)
605
606        self.assertRaises(TypeError, sys.settrace)
607
608    def testEvalExecFreeVars(self):
609
610        def f(x):
611            return lambda: x + 1
612
613        g = f(3)
614        self.assertRaises(TypeError, eval, g.__code__)
615
616        try:
617            exec(g.__code__, {})
618        except TypeError:
619            pass
620        else:
621            self.fail("exec should have failed, because code contained free vars")
622
623    def testListCompLocalVars(self):
624
625        try:
626            print(bad)
627        except NameError:
628            pass
629        else:
630            print("bad should not be defined")
631
632        def x():
633            [bad for s in 'a b' for bad in s.split()]
634
635        x()
636        try:
637            print(bad)
638        except NameError:
639            pass
640
641    def testEvalFreeVars(self):
642
643        def f(x):
644            def g():
645                x
646                eval("x + 1")
647            return g
648
649        f(4)()
650
651    def testFreeingCell(self):
652        # Test what happens when a finalizer accesses
653        # the cell where the object was stored.
654        class Special:
655            def __del__(self):
656                nestedcell_get()
657
658    def testNonLocalFunction(self):
659
660        def f(x):
661            def inc():
662                nonlocal x
663                x += 1
664                return x
665            def dec():
666                nonlocal x
667                x -= 1
668                return x
669            return inc, dec
670
671        inc, dec = f(0)
672        self.assertEqual(inc(), 1)
673        self.assertEqual(inc(), 2)
674        self.assertEqual(dec(), 1)
675        self.assertEqual(dec(), 0)
676
677    def testNonLocalMethod(self):
678        def f(x):
679            class c:
680                def inc(self):
681                    nonlocal x
682                    x += 1
683                    return x
684                def dec(self):
685                    nonlocal x
686                    x -= 1
687                    return x
688            return c()
689        c = f(0)
690        self.assertEqual(c.inc(), 1)
691        self.assertEqual(c.inc(), 2)
692        self.assertEqual(c.dec(), 1)
693        self.assertEqual(c.dec(), 0)
694
695    def testGlobalInParallelNestedFunctions(self):
696        # A symbol table bug leaked the global statement from one
697        # function to other nested functions in the same block.
698        # This test verifies that a global statement in the first
699        # function does not affect the second function.
700        local_ns = {}
701        global_ns = {}
702        exec("""if 1:
703            def f():
704                y = 1
705                def g():
706                    global y
707                    return y
708                def h():
709                    return y + 1
710                return g, h
711            y = 9
712            g, h = f()
713            result9 = g()
714            result2 = h()
715            """, local_ns, global_ns)
716        self.assertEqual(2, global_ns["result2"])
717        self.assertEqual(9, global_ns["result9"])
718
719    def testNonLocalClass(self):
720
721        def f(x):
722            class c:
723                nonlocal x
724                x += 1
725                def get(self):
726                    return x
727            return c()
728
729        c = f(0)
730        self.assertEqual(c.get(), 1)
731        self.assertNotIn("x", c.__class__.__dict__)
732
733
734    def testNonLocalGenerator(self):
735
736        def f(x):
737            def g(y):
738                nonlocal x
739                for i in range(y):
740                    x += 1
741                    yield x
742            return g
743
744        g = f(0)
745        self.assertEqual(list(g(5)), [1, 2, 3, 4, 5])
746
747    def testNestedNonLocal(self):
748
749        def f(x):
750            def g():
751                nonlocal x
752                x -= 2
753                def h():
754                    nonlocal x
755                    x += 4
756                    return x
757                return h
758            return g
759
760        g = f(1)
761        h = g()
762        self.assertEqual(h(), 3)
763
764    def testTopIsNotSignificant(self):
765        # See #9997.
766        def top(a):
767            pass
768        def b():
769            global a
770
771    def testClassNamespaceOverridesClosure(self):
772        # See #17853.
773        x = 42
774        class X:
775            locals()["x"] = 43
776            y = x
777        self.assertEqual(X.y, 43)
778        class X:
779            locals()["x"] = 43
780            del x
781        self.assertFalse(hasattr(X, "x"))
782        self.assertEqual(x, 42)
783
784    @cpython_only
785    def testCellLeak(self):
786        # Issue 17927.
787        #
788        # The issue was that if self was part of a cycle involving the
789        # frame of a method call, *and* the method contained a nested
790        # function referencing self, thereby forcing 'self' into a
791        # cell, setting self to None would not be enough to break the
792        # frame -- the frame had another reference to the instance,
793        # which could not be cleared by the code running in the frame
794        # (though it will be cleared when the frame is collected).
795        # Without the lambda, setting self to None is enough to break
796        # the cycle.
797        class Tester:
798            def dig(self):
799                if 0:
800                    lambda: self
801                try:
802                    1/0
803                except Exception as exc:
804                    self.exc = exc
805                self = None  # Break the cycle
806        tester = Tester()
807        tester.dig()
808        ref = weakref.ref(tester)
809        del tester
810        gc_collect()  # For PyPy or other GCs.
811        self.assertIsNone(ref())
812
813
814if __name__ == '__main__':
815    unittest.main()
816