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