| import unittest | 
 | from test.test_support import check_syntax_error, run_unittest | 
 |  | 
 | import warnings | 
 | warnings.filterwarnings("ignore", r"import \*", SyntaxWarning, "<test string>") | 
 | warnings.filterwarnings("ignore", r"import \*", SyntaxWarning, "<string>") | 
 |  | 
 | class ScopeTests(unittest.TestCase): | 
 |  | 
 |     def testSimpleNesting(self): | 
 |  | 
 |         def make_adder(x): | 
 |             def adder(y): | 
 |                 return x + y | 
 |             return adder | 
 |  | 
 |         inc = make_adder(1) | 
 |         plus10 = make_adder(10) | 
 |  | 
 |         self.assertEqual(inc(1), 2) | 
 |         self.assertEqual(plus10(-2), 8) | 
 |  | 
 |     def testExtraNesting(self): | 
 |  | 
 |         def make_adder2(x): | 
 |             def extra(): # check freevars passing through non-use scopes | 
 |                 def adder(y): | 
 |                     return x + y | 
 |                 return adder | 
 |             return extra() | 
 |  | 
 |         inc = make_adder2(1) | 
 |         plus10 = make_adder2(10) | 
 |  | 
 |         self.assertEqual(inc(1), 2) | 
 |         self.assertEqual(plus10(-2), 8) | 
 |  | 
 |     def testSimpleAndRebinding(self): | 
 |  | 
 |         def make_adder3(x): | 
 |             def adder(y): | 
 |                 return x + y | 
 |             x = x + 1 # check tracking of assignment to x in defining scope | 
 |             return adder | 
 |  | 
 |         inc = make_adder3(0) | 
 |         plus10 = make_adder3(9) | 
 |  | 
 |         self.assertEqual(inc(1), 2) | 
 |         self.assertEqual(plus10(-2), 8) | 
 |  | 
 |     def testNestingGlobalNoFree(self): | 
 |  | 
 |         def make_adder4(): # XXX add exta level of indirection | 
 |             def nest(): | 
 |                 def nest(): | 
 |                     def adder(y): | 
 |                         return global_x + y # check that plain old globals work | 
 |                     return adder | 
 |                 return nest() | 
 |             return nest() | 
 |  | 
 |         global_x = 1 | 
 |         adder = make_adder4() | 
 |         self.assertEqual(adder(1), 2) | 
 |  | 
 |         global_x = 10 | 
 |         self.assertEqual(adder(-2), 8) | 
 |  | 
 |     def testNestingThroughClass(self): | 
 |  | 
 |         def make_adder5(x): | 
 |             class Adder: | 
 |                 def __call__(self, y): | 
 |                     return x + y | 
 |             return Adder() | 
 |  | 
 |         inc = make_adder5(1) | 
 |         plus10 = make_adder5(10) | 
 |  | 
 |         self.assertEqual(inc(1), 2) | 
 |         self.assertEqual(plus10(-2), 8) | 
 |  | 
 |     def testNestingPlusFreeRefToGlobal(self): | 
 |  | 
 |         def make_adder6(x): | 
 |             global global_nest_x | 
 |             def adder(y): | 
 |                 return global_nest_x + y | 
 |             global_nest_x = x | 
 |             return adder | 
 |  | 
 |         inc = make_adder6(1) | 
 |         plus10 = make_adder6(10) | 
 |  | 
 |         self.assertEqual(inc(1), 11) # there's only one global | 
 |         self.assertEqual(plus10(-2), 8) | 
 |  | 
 |     def testNearestEnclosingScope(self): | 
 |  | 
 |         def f(x): | 
 |             def g(y): | 
 |                 x = 42 # check that this masks binding in f() | 
 |                 def h(z): | 
 |                     return x + z | 
 |                 return h | 
 |             return g(2) | 
 |  | 
 |         test_func = f(10) | 
 |         self.assertEqual(test_func(5), 47) | 
 |  | 
 |     def testMixedFreevarsAndCellvars(self): | 
 |  | 
 |         def identity(x): | 
 |             return x | 
 |  | 
 |         def f(x, y, z): | 
 |             def g(a, b, c): | 
 |                 a = a + x # 3 | 
 |                 def h(): | 
 |                     # z * (4 + 9) | 
 |                     # 3 * 13 | 
 |                     return identity(z * (b + y)) | 
 |                 y = c + z # 9 | 
 |                 return h | 
 |             return g | 
 |  | 
 |         g = f(1, 2, 3) | 
 |         h = g(2, 4, 6) | 
 |         self.assertEqual(h(), 39) | 
 |  | 
 |     def testFreeVarInMethod(self): | 
 |  | 
 |         def test(): | 
 |             method_and_var = "var" | 
 |             class Test: | 
 |                 def method_and_var(self): | 
 |                     return "method" | 
 |                 def test(self): | 
 |                     return method_and_var | 
 |                 def actual_global(self): | 
 |                     return str("global") | 
 |                 def str(self): | 
 |                     return str(self) | 
 |             return Test() | 
 |  | 
 |         t = test() | 
 |         self.assertEqual(t.test(), "var") | 
 |         self.assertEqual(t.method_and_var(), "method") | 
 |         self.assertEqual(t.actual_global(), "global") | 
 |  | 
 |         method_and_var = "var" | 
 |         class Test: | 
 |             # this class is not nested, so the rules are different | 
 |             def method_and_var(self): | 
 |                 return "method" | 
 |             def test(self): | 
 |                 return method_and_var | 
 |             def actual_global(self): | 
 |                 return str("global") | 
 |             def str(self): | 
 |                 return str(self) | 
 |  | 
 |         t = Test() | 
 |         self.assertEqual(t.test(), "var") | 
 |         self.assertEqual(t.method_and_var(), "method") | 
 |         self.assertEqual(t.actual_global(), "global") | 
 |  | 
 |     def testRecursion(self): | 
 |  | 
 |         def f(x): | 
 |             def fact(n): | 
 |                 if n == 0: | 
 |                     return 1 | 
 |                 else: | 
 |                     return n * fact(n - 1) | 
 |             if x >= 0: | 
 |                 return fact(x) | 
 |             else: | 
 |                 raise ValueError, "x must be >= 0" | 
 |  | 
 |         self.assertEqual(f(6), 720) | 
 |  | 
 |  | 
 |     def testUnoptimizedNamespaces(self): | 
 |  | 
 |         check_syntax_error(self, """\ | 
 | def unoptimized_clash1(strip): | 
 |     def f(s): | 
 |         from string import * | 
 |         return strip(s) # ambiguity: free or local | 
 |     return f | 
 | """) | 
 |  | 
 |         check_syntax_error(self, """\ | 
 | def unoptimized_clash2(): | 
 |     from string import * | 
 |     def f(s): | 
 |         return strip(s) # ambiguity: global or local | 
 |     return f | 
 | """) | 
 |  | 
 |         check_syntax_error(self, """\ | 
 | def unoptimized_clash2(): | 
 |     from string import * | 
 |     def g(): | 
 |         def f(s): | 
 |             return strip(s) # ambiguity: global or local | 
 |         return f | 
 | """) | 
 |  | 
 |         # XXX could allow this for exec with const argument, but what's the point | 
 |         check_syntax_error(self, """\ | 
 | def error(y): | 
 |     exec "a = 1" | 
 |     def f(x): | 
 |         return x + y | 
 |     return f | 
 | """) | 
 |  | 
 |         check_syntax_error(self, """\ | 
 | def f(x): | 
 |     def g(): | 
 |         return x | 
 |     del x # can't del name | 
 | """) | 
 |  | 
 |         check_syntax_error(self, """\ | 
 | def f(): | 
 |     def g(): | 
 |         from string import * | 
 |         return strip # global or local? | 
 | """) | 
 |  | 
 |         # and verify a few cases that should work | 
 |  | 
 |         exec """ | 
 | def noproblem1(): | 
 |     from string import * | 
 |     f = lambda x:x | 
 |  | 
 | def noproblem2(): | 
 |     from string import * | 
 |     def f(x): | 
 |         return x + 1 | 
 |  | 
 | def noproblem3(): | 
 |     from string import * | 
 |     def f(x): | 
 |         global y | 
 |         y = x | 
 | """ | 
 |  | 
 |     def testLambdas(self): | 
 |  | 
 |         f1 = lambda x: lambda y: x + y | 
 |         inc = f1(1) | 
 |         plus10 = f1(10) | 
 |         self.assertEqual(inc(1), 2) | 
 |         self.assertEqual(plus10(5), 15) | 
 |  | 
 |         f2 = lambda x: (lambda : lambda y: x + y)() | 
 |         inc = f2(1) | 
 |         plus10 = f2(10) | 
 |         self.assertEqual(inc(1), 2) | 
 |         self.assertEqual(plus10(5), 15) | 
 |  | 
 |         f3 = lambda x: lambda y: global_x + y | 
 |         global_x = 1 | 
 |         inc = f3(None) | 
 |         self.assertEqual(inc(2), 3) | 
 |  | 
 |         f8 = lambda x, y, z: lambda a, b, c: lambda : z * (b + y) | 
 |         g = f8(1, 2, 3) | 
 |         h = g(2, 4, 6) | 
 |         self.assertEqual(h(), 18) | 
 |  | 
 |     def testUnboundLocal(self): | 
 |  | 
 |         def errorInOuter(): | 
 |             print y | 
 |             def inner(): | 
 |                 return y | 
 |             y = 1 | 
 |  | 
 |         def errorInInner(): | 
 |             def inner(): | 
 |                 return y | 
 |             inner() | 
 |             y = 1 | 
 |  | 
 |         self.assertRaises(UnboundLocalError, errorInOuter) | 
 |         self.assertRaises(NameError, errorInInner) | 
 |  | 
 |         # test for bug #1501934: incorrect LOAD/STORE_GLOBAL generation | 
 |         exec """ | 
 | global_x = 1 | 
 | def f(): | 
 |     global_x += 1 | 
 | try: | 
 |     f() | 
 | except UnboundLocalError: | 
 |     pass | 
 | else: | 
 |     fail('scope of global_x not correctly determined') | 
 | """ in {'fail': self.fail} | 
 |  | 
 |     def testComplexDefinitions(self): | 
 |  | 
 |         def makeReturner(*lst): | 
 |             def returner(): | 
 |                 return lst | 
 |             return returner | 
 |  | 
 |         self.assertEqual(makeReturner(1,2,3)(), (1,2,3)) | 
 |  | 
 |         def makeReturner2(**kwargs): | 
 |             def returner(): | 
 |                 return kwargs | 
 |             return returner | 
 |  | 
 |         self.assertEqual(makeReturner2(a=11)()['a'], 11) | 
 |  | 
 |         def makeAddPair((a, b)): | 
 |             def addPair((c, d)): | 
 |                 return (a + c, b + d) | 
 |             return addPair | 
 |  | 
 |         self.assertEqual(makeAddPair((1, 2))((100, 200)), (101,202)) | 
 |  | 
 |     def testScopeOfGlobalStmt(self): | 
 | # Examples posted by Samuele Pedroni to python-dev on 3/1/2001 | 
 |  | 
 |         exec """\ | 
 | # I | 
 | x = 7 | 
 | def f(): | 
 |     x = 1 | 
 |     def g(): | 
 |         global x | 
 |         def i(): | 
 |             def h(): | 
 |                 return x | 
 |             return h() | 
 |         return i() | 
 |     return g() | 
 | self.assertEqual(f(), 7) | 
 | self.assertEqual(x, 7) | 
 |  | 
 | # II | 
 | x = 7 | 
 | def f(): | 
 |     x = 1 | 
 |     def g(): | 
 |         x = 2 | 
 |         def i(): | 
 |             def h(): | 
 |                 return x | 
 |             return h() | 
 |         return i() | 
 |     return g() | 
 | self.assertEqual(f(), 2) | 
 | self.assertEqual(x, 7) | 
 |  | 
 | # III | 
 | x = 7 | 
 | def f(): | 
 |     x = 1 | 
 |     def g(): | 
 |         global x | 
 |         x = 2 | 
 |         def i(): | 
 |             def h(): | 
 |                 return x | 
 |             return h() | 
 |         return i() | 
 |     return g() | 
 | self.assertEqual(f(), 2) | 
 | self.assertEqual(x, 2) | 
 |  | 
 | # IV | 
 | x = 7 | 
 | def f(): | 
 |     x = 3 | 
 |     def g(): | 
 |         global x | 
 |         x = 2 | 
 |         def i(): | 
 |             def h(): | 
 |                 return x | 
 |             return h() | 
 |         return i() | 
 |     return g() | 
 | self.assertEqual(f(), 2) | 
 | self.assertEqual(x, 2) | 
 |  | 
 | # XXX what about global statements in class blocks? | 
 | # do they affect methods? | 
 |  | 
 | x = 12 | 
 | class Global: | 
 |     global x | 
 |     x = 13 | 
 |     def set(self, val): | 
 |         x = val | 
 |     def get(self): | 
 |         return x | 
 |  | 
 | g = Global() | 
 | self.assertEqual(g.get(), 13) | 
 | g.set(15) | 
 | self.assertEqual(g.get(), 13) | 
 | """ | 
 |  | 
 |     def testLeaks(self): | 
 |  | 
 |         class Foo: | 
 |             count = 0 | 
 |  | 
 |             def __init__(self): | 
 |                 Foo.count += 1 | 
 |  | 
 |             def __del__(self): | 
 |                 Foo.count -= 1 | 
 |  | 
 |         def f1(): | 
 |             x = Foo() | 
 |             def f2(): | 
 |                 return x | 
 |             f2() | 
 |  | 
 |         for i in range(100): | 
 |             f1() | 
 |  | 
 |         self.assertEqual(Foo.count, 0) | 
 |  | 
 |     def testClassAndGlobal(self): | 
 |  | 
 |         exec """\ | 
 | def test(x): | 
 |     class Foo: | 
 |         global x | 
 |         def __call__(self, y): | 
 |             return x + y | 
 |     return Foo() | 
 |  | 
 | x = 0 | 
 | self.assertEqual(test(6)(2), 8) | 
 | x = -1 | 
 | self.assertEqual(test(3)(2), 5) | 
 |  | 
 | looked_up_by_load_name = False | 
 | class X: | 
 |     # Implicit globals inside classes are be looked up by LOAD_NAME, not | 
 |     # LOAD_GLOBAL. | 
 |     locals()['looked_up_by_load_name'] = True | 
 |     passed = looked_up_by_load_name | 
 |  | 
 | self.assertTrue(X.passed) | 
 | """ | 
 |  | 
 |     def testLocalsFunction(self): | 
 |  | 
 |         def f(x): | 
 |             def g(y): | 
 |                 def h(z): | 
 |                     return y + z | 
 |                 w = x + y | 
 |                 y += 3 | 
 |                 return locals() | 
 |             return g | 
 |  | 
 |         d = f(2)(4) | 
 |         self.assertTrue(d.has_key('h')) | 
 |         del d['h'] | 
 |         self.assertEqual(d, {'x': 2, 'y': 7, 'w': 6}) | 
 |  | 
 |     def testLocalsClass(self): | 
 |         # This test verifies that calling locals() does not pollute | 
 |         # the local namespace of the class with free variables.  Old | 
 |         # versions of Python had a bug, where a free variable being | 
 |         # passed through a class namespace would be inserted into | 
 |         # locals() by locals() or exec or a trace function. | 
 |         # | 
 |         # The real bug lies in frame code that copies variables | 
 |         # between fast locals and the locals dict, e.g. when executing | 
 |         # a trace function. | 
 |  | 
 |         def f(x): | 
 |             class C: | 
 |                 x = 12 | 
 |                 def m(self): | 
 |                     return x | 
 |                 locals() | 
 |             return C | 
 |  | 
 |         self.assertEqual(f(1).x, 12) | 
 |  | 
 |         def f(x): | 
 |             class C: | 
 |                 y = x | 
 |                 def m(self): | 
 |                     return x | 
 |                 z = list(locals()) | 
 |             return C | 
 |  | 
 |         varnames = f(1).z | 
 |         self.assertNotIn("x", varnames) | 
 |         self.assertIn("y", varnames) | 
 |  | 
 |     def testLocalsClass_WithTrace(self): | 
 |         # Issue23728: after the trace function returns, the locals() | 
 |         # dictionary is used to update all variables, this used to | 
 |         # include free variables. But in class statements, free | 
 |         # variables are not inserted... | 
 |         import sys | 
 |         sys.settrace(lambda a,b,c:None) | 
 |         try: | 
 |             x = 12 | 
 |  | 
 |             class C: | 
 |                 def f(self): | 
 |                     return x | 
 |  | 
 |             self.assertEquals(x, 12) # Used to raise UnboundLocalError | 
 |         finally: | 
 |             sys.settrace(None) | 
 |  | 
 |     def testBoundAndFree(self): | 
 |         # var is bound and free in class | 
 |  | 
 |         def f(x): | 
 |             class C: | 
 |                 def m(self): | 
 |                     return x | 
 |                 a = x | 
 |             return C | 
 |  | 
 |         inst = f(3)() | 
 |         self.assertEqual(inst.a, inst.m()) | 
 |  | 
 |     def testInteractionWithTraceFunc(self): | 
 |  | 
 |         import sys | 
 |         def tracer(a,b,c): | 
 |             return tracer | 
 |  | 
 |         def adaptgetter(name, klass, getter): | 
 |             kind, des = getter | 
 |             if kind == 1:       # AV happens when stepping from this line to next | 
 |                 if des == "": | 
 |                     des = "_%s__%s" % (klass.__name__, name) | 
 |                 return lambda obj: getattr(obj, des) | 
 |  | 
 |         class TestClass: | 
 |             pass | 
 |  | 
 |         sys.settrace(tracer) | 
 |         adaptgetter("foo", TestClass, (1, "")) | 
 |         sys.settrace(None) | 
 |  | 
 |         self.assertRaises(TypeError, sys.settrace) | 
 |  | 
 |     def testEvalExecFreeVars(self): | 
 |  | 
 |         def f(x): | 
 |             return lambda: x + 1 | 
 |  | 
 |         g = f(3) | 
 |         self.assertRaises(TypeError, eval, g.func_code) | 
 |  | 
 |         try: | 
 |             exec g.func_code in {} | 
 |         except TypeError: | 
 |             pass | 
 |         else: | 
 |             self.fail("exec should have failed, because code contained free vars") | 
 |  | 
 |     def testListCompLocalVars(self): | 
 |  | 
 |         try: | 
 |             print bad | 
 |         except NameError: | 
 |             pass | 
 |         else: | 
 |             print "bad should not be defined" | 
 |  | 
 |         def x(): | 
 |             [bad for s in 'a b' for bad in s.split()] | 
 |  | 
 |         x() | 
 |         try: | 
 |             print bad | 
 |         except NameError: | 
 |             pass | 
 |  | 
 |     def testEvalFreeVars(self): | 
 |  | 
 |         def f(x): | 
 |             def g(): | 
 |                 x | 
 |                 eval("x + 1") | 
 |             return g | 
 |  | 
 |         f(4)() | 
 |  | 
 |     def testFreeingCell(self): | 
 |         # Test what happens when a finalizer accesses | 
 |         # the cell where the object was stored. | 
 |         class Special: | 
 |             def __del__(self): | 
 |                 nestedcell_get() | 
 |  | 
 |         def f(): | 
 |             global nestedcell_get | 
 |             def nestedcell_get(): | 
 |                 return c | 
 |  | 
 |             c = (Special(),) | 
 |             c = 2 | 
 |  | 
 |         f() # used to crash the interpreter... | 
 |  | 
 |     def testGlobalInParallelNestedFunctions(self): | 
 |         # A symbol table bug leaked the global statement from one | 
 |         # function to other nested functions in the same block. | 
 |         # This test verifies that a global statement in the first | 
 |         # function does not affect the second function. | 
 |         CODE = """def f(): | 
 |     y = 1 | 
 |     def g(): | 
 |         global y | 
 |         return y | 
 |     def h(): | 
 |         return y + 1 | 
 |     return g, h | 
 |  | 
 | y = 9 | 
 | g, h = f() | 
 | result9 = g() | 
 | result2 = h() | 
 | """ | 
 |         local_ns = {} | 
 |         global_ns = {} | 
 |         exec CODE in local_ns, global_ns | 
 |         self.assertEqual(2, global_ns["result2"]) | 
 |         self.assertEqual(9, global_ns["result9"]) | 
 |  | 
 |  | 
 | def test_main(): | 
 |     run_unittest(ScopeTests) | 
 |  | 
 | if __name__ == '__main__': | 
 |     test_main() |