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 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 gc_collect() # For PyPy or other GCs. 427 self.assertEqual(Foo.count, 0) 428 429 def testClassAndGlobal(self): 430 431 exec("""if 1: 432 def test(x): 433 class Foo: 434 global x 435 def __call__(self, y): 436 return x + y 437 return Foo() 438 439 x = 0 440 self.assertEqual(test(6)(2), 8) 441 x = -1 442 self.assertEqual(test(3)(2), 5) 443 444 looked_up_by_load_name = False 445 class X: 446 # Implicit globals inside classes are be looked up by LOAD_NAME, not 447 # LOAD_GLOBAL. 448 locals()['looked_up_by_load_name'] = True 449 passed = looked_up_by_load_name 450 451 self.assertTrue(X.passed) 452 """) 453 454 def testLocalsFunction(self): 455 456 def f(x): 457 def g(y): 458 def h(z): 459 return y + z 460 w = x + y 461 y += 3 462 return locals() 463 return g 464 465 d = f(2)(4) 466 self.assertIn('h', d) 467 del d['h'] 468 self.assertEqual(d, {'x': 2, 'y': 7, 'w': 6}) 469 470 def testLocalsClass(self): 471 # This test verifies that calling locals() does not pollute 472 # the local namespace of the class with free variables. Old 473 # versions of Python had a bug, where a free variable being 474 # passed through a class namespace would be inserted into 475 # locals() by locals() or exec or a trace function. 476 # 477 # The real bug lies in frame code that copies variables 478 # between fast locals and the locals dict, e.g. when executing 479 # a trace function. 480 481 def f(x): 482 class C: 483 x = 12 484 def m(self): 485 return x 486 locals() 487 return C 488 489 self.assertEqual(f(1).x, 12) 490 491 def f(x): 492 class C: 493 y = x 494 def m(self): 495 return x 496 z = list(locals()) 497 return C 498 499 varnames = f(1).z 500 self.assertNotIn("x", varnames) 501 self.assertIn("y", varnames) 502 503 @cpython_only 504 def testLocalsClass_WithTrace(self): 505 # Issue23728: after the trace function returns, the locals() 506 # dictionary is used to update all variables, this used to 507 # include free variables. But in class statements, free 508 # variables are not inserted... 509 import sys 510 self.addCleanup(sys.settrace, sys.gettrace()) 511 sys.settrace(lambda a,b,c:None) 512 x = 12 513 514 class C: 515 def f(self): 516 return x 517 518 self.assertEqual(x, 12) # Used to raise UnboundLocalError 519 520 def testBoundAndFree(self): 521 # var is bound and free in class 522 523 def f(x): 524 class C: 525 def m(self): 526 return x 527 a = x 528 return C 529 530 inst = f(3)() 531 self.assertEqual(inst.a, inst.m()) 532 533 @cpython_only 534 def testInteractionWithTraceFunc(self): 535 536 import sys 537 def tracer(a,b,c): 538 return tracer 539 540 def adaptgetter(name, klass, getter): 541 kind, des = getter 542 if kind == 1: # AV happens when stepping from this line to next 543 if des == "": 544 des = "_%s__%s" % (klass.__name__, name) 545 return lambda obj: getattr(obj, des) 546 547 class TestClass: 548 pass 549 550 self.addCleanup(sys.settrace, sys.gettrace()) 551 sys.settrace(tracer) 552 adaptgetter("foo", TestClass, (1, "")) 553 sys.settrace(None) 554 555 self.assertRaises(TypeError, sys.settrace) 556 557 def testEvalExecFreeVars(self): 558 559 def f(x): 560 return lambda: x + 1 561 562 g = f(3) 563 self.assertRaises(TypeError, eval, g.__code__) 564 565 try: 566 exec(g.__code__, {}) 567 except TypeError: 568 pass 569 else: 570 self.fail("exec should have failed, because code contained free vars") 571 572 def testListCompLocalVars(self): 573 574 try: 575 print(bad) 576 except NameError: 577 pass 578 else: 579 print("bad should not be defined") 580 581 def x(): 582 [bad for s in 'a b' for bad in s.split()] 583 584 x() 585 try: 586 print(bad) 587 except NameError: 588 pass 589 590 def testEvalFreeVars(self): 591 592 def f(x): 593 def g(): 594 x 595 eval("x + 1") 596 return g 597 598 f(4)() 599 600 def testFreeingCell(self): 601 # Test what happens when a finalizer accesses 602 # the cell where the object was stored. 603 class Special: 604 def __del__(self): 605 nestedcell_get() 606 607 def testNonLocalFunction(self): 608 609 def f(x): 610 def inc(): 611 nonlocal x 612 x += 1 613 return x 614 def dec(): 615 nonlocal x 616 x -= 1 617 return x 618 return inc, dec 619 620 inc, dec = f(0) 621 self.assertEqual(inc(), 1) 622 self.assertEqual(inc(), 2) 623 self.assertEqual(dec(), 1) 624 self.assertEqual(dec(), 0) 625 626 def testNonLocalMethod(self): 627 def f(x): 628 class c: 629 def inc(self): 630 nonlocal x 631 x += 1 632 return x 633 def dec(self): 634 nonlocal x 635 x -= 1 636 return x 637 return c() 638 c = f(0) 639 self.assertEqual(c.inc(), 1) 640 self.assertEqual(c.inc(), 2) 641 self.assertEqual(c.dec(), 1) 642 self.assertEqual(c.dec(), 0) 643 644 def testGlobalInParallelNestedFunctions(self): 645 # A symbol table bug leaked the global statement from one 646 # function to other nested functions in the same block. 647 # This test verifies that a global statement in the first 648 # function does not affect the second function. 649 local_ns = {} 650 global_ns = {} 651 exec("""if 1: 652 def f(): 653 y = 1 654 def g(): 655 global y 656 return y 657 def h(): 658 return y + 1 659 return g, h 660 y = 9 661 g, h = f() 662 result9 = g() 663 result2 = h() 664 """, local_ns, global_ns) 665 self.assertEqual(2, global_ns["result2"]) 666 self.assertEqual(9, global_ns["result9"]) 667 668 def testNonLocalClass(self): 669 670 def f(x): 671 class c: 672 nonlocal x 673 x += 1 674 def get(self): 675 return x 676 return c() 677 678 c = f(0) 679 self.assertEqual(c.get(), 1) 680 self.assertNotIn("x", c.__class__.__dict__) 681 682 683 def testNonLocalGenerator(self): 684 685 def f(x): 686 def g(y): 687 nonlocal x 688 for i in range(y): 689 x += 1 690 yield x 691 return g 692 693 g = f(0) 694 self.assertEqual(list(g(5)), [1, 2, 3, 4, 5]) 695 696 def testNestedNonLocal(self): 697 698 def f(x): 699 def g(): 700 nonlocal x 701 x -= 2 702 def h(): 703 nonlocal x 704 x += 4 705 return x 706 return h 707 return g 708 709 g = f(1) 710 h = g() 711 self.assertEqual(h(), 3) 712 713 def testTopIsNotSignificant(self): 714 # See #9997. 715 def top(a): 716 pass 717 def b(): 718 global a 719 720 def testClassNamespaceOverridesClosure(self): 721 # See #17853. 722 x = 42 723 class X: 724 locals()["x"] = 43 725 y = x 726 self.assertEqual(X.y, 43) 727 class X: 728 locals()["x"] = 43 729 del x 730 self.assertFalse(hasattr(X, "x")) 731 self.assertEqual(x, 42) 732 733 @cpython_only 734 def testCellLeak(self): 735 # Issue 17927. 736 # 737 # The issue was that if self was part of a cycle involving the 738 # frame of a method call, *and* the method contained a nested 739 # function referencing self, thereby forcing 'self' into a 740 # cell, setting self to None would not be enough to break the 741 # frame -- the frame had another reference to the instance, 742 # which could not be cleared by the code running in the frame 743 # (though it will be cleared when the frame is collected). 744 # Without the lambda, setting self to None is enough to break 745 # the cycle. 746 class Tester: 747 def dig(self): 748 if 0: 749 lambda: self 750 try: 751 1/0 752 except Exception as exc: 753 self.exc = exc 754 self = None # Break the cycle 755 tester = Tester() 756 tester.dig() 757 ref = weakref.ref(tester) 758 del tester 759 gc_collect() # For PyPy or other GCs. 760 self.assertIsNone(ref()) 761 762 763if __name__ == '__main__': 764 unittest.main() 765