test_scope.py revision 33d2689fc900a814f0a7d2f846abe0c34024ae17
1import unittest 2from test.test_support import check_syntax_error, run_unittest 3 4import warnings 5warnings.filterwarnings("ignore", r"import \*", SyntaxWarning, "<test string>") 6warnings.filterwarnings("ignore", r"import \*", SyntaxWarning, "<string>") 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 testRecursion(self): 170 171 def f(x): 172 def fact(n): 173 if n == 0: 174 return 1 175 else: 176 return n * fact(n - 1) 177 if x >= 0: 178 return fact(x) 179 else: 180 raise ValueError, "x must be >= 0" 181 182 self.assertEqual(f(6), 720) 183 184 185 def testUnoptimizedNamespaces(self): 186 187 check_syntax_error(self, """\ 188def unoptimized_clash1(strip): 189 def f(s): 190 from sys import * 191 return getrefcount(s) # ambiguity: free or local 192 return f 193""") 194 195 check_syntax_error(self, """\ 196def unoptimized_clash2(): 197 from sys import * 198 def f(s): 199 return getrefcount(s) # ambiguity: global or local 200 return f 201""") 202 203 check_syntax_error(self, """\ 204def unoptimized_clash2(): 205 from sys import * 206 def g(): 207 def f(s): 208 return getrefcount(s) # ambiguity: global or local 209 return f 210""") 211 212 check_syntax_error(self, """\ 213def f(x): 214 def g(): 215 return x 216 del x # can't del name 217""") 218 219 check_syntax_error(self, """\ 220def f(): 221 def g(): 222 from sys import * 223 return getrefcount # global or local? 224""") 225 226 def testLambdas(self): 227 228 f1 = lambda x: lambda y: x + y 229 inc = f1(1) 230 plus10 = f1(10) 231 self.assertEqual(inc(1), 2) 232 self.assertEqual(plus10(5), 15) 233 234 f2 = lambda x: (lambda : lambda y: x + y)() 235 inc = f2(1) 236 plus10 = f2(10) 237 self.assertEqual(inc(1), 2) 238 self.assertEqual(plus10(5), 15) 239 240 f3 = lambda x: lambda y: global_x + y 241 global_x = 1 242 inc = f3(None) 243 self.assertEqual(inc(2), 3) 244 245 f8 = lambda x, y, z: lambda a, b, c: lambda : z * (b + y) 246 g = f8(1, 2, 3) 247 h = g(2, 4, 6) 248 self.assertEqual(h(), 18) 249 250 def testUnboundLocal(self): 251 252 def errorInOuter(): 253 print(y) 254 def inner(): 255 return y 256 y = 1 257 258 def errorInInner(): 259 def inner(): 260 return y 261 inner() 262 y = 1 263 264 try: 265 errorInOuter() 266 except UnboundLocalError: 267 pass 268 else: 269 self.fail() 270 271 try: 272 errorInInner() 273 except NameError: 274 pass 275 else: 276 self.fail() 277 278 # test for bug #1501934: incorrect LOAD/STORE_GLOBAL generation 279 exec(""" 280global_x = 1 281def f(): 282 global_x += 1 283try: 284 f() 285except UnboundLocalError: 286 pass 287else: 288 fail('scope of global_x not correctly determined') 289""", {'fail': self.fail}) 290 291 def testComplexDefinitions(self): 292 293 def makeReturner(*lst): 294 def returner(): 295 return lst 296 return returner 297 298 self.assertEqual(makeReturner(1,2,3)(), (1,2,3)) 299 300 def makeReturner2(**kwargs): 301 def returner(): 302 return kwargs 303 return returner 304 305 self.assertEqual(makeReturner2(a=11)()['a'], 11) 306 307 def testScopeOfGlobalStmt(self): 308# Examples posted by Samuele Pedroni to python-dev on 3/1/2001 309 310 exec("""\ 311# I 312x = 7 313def f(): 314 x = 1 315 def g(): 316 global x 317 def i(): 318 def h(): 319 return x 320 return h() 321 return i() 322 return g() 323self.assertEqual(f(), 7) 324self.assertEqual(x, 7) 325 326# II 327x = 7 328def f(): 329 x = 1 330 def g(): 331 x = 2 332 def i(): 333 def h(): 334 return x 335 return h() 336 return i() 337 return g() 338self.assertEqual(f(), 2) 339self.assertEqual(x, 7) 340 341# III 342x = 7 343def f(): 344 x = 1 345 def g(): 346 global x 347 x = 2 348 def i(): 349 def h(): 350 return x 351 return h() 352 return i() 353 return g() 354self.assertEqual(f(), 2) 355self.assertEqual(x, 2) 356 357# IV 358x = 7 359def f(): 360 x = 3 361 def g(): 362 global x 363 x = 2 364 def i(): 365 def h(): 366 return x 367 return h() 368 return i() 369 return g() 370self.assertEqual(f(), 2) 371self.assertEqual(x, 2) 372 373# XXX what about global statements in class blocks? 374# do they affect methods? 375 376x = 12 377class Global: 378 global x 379 x = 13 380 def set(self, val): 381 x = val 382 def get(self): 383 return x 384 385g = Global() 386self.assertEqual(g.get(), 13) 387g.set(15) 388self.assertEqual(g.get(), 13) 389""") 390 391 def testLeaks(self): 392 393 class Foo: 394 count = 0 395 396 def __init__(self): 397 Foo.count += 1 398 399 def __del__(self): 400 Foo.count -= 1 401 402 def f1(): 403 x = Foo() 404 def f2(): 405 return x 406 f2() 407 408 for i in range(100): 409 f1() 410 411 self.assertEqual(Foo.count, 0) 412 413 def testClassAndGlobal(self): 414 415 exec("""\ 416def test(x): 417 class Foo: 418 global x 419 def __call__(self, y): 420 return x + y 421 return Foo() 422 423x = 0 424self.assertEqual(test(6)(2), 8) 425x = -1 426self.assertEqual(test(3)(2), 5) 427 428looked_up_by_load_name = False 429class X: 430 # Implicit globals inside classes are be looked up by LOAD_NAME, not 431 # LOAD_GLOBAL. 432 locals()['looked_up_by_load_name'] = True 433 passed = looked_up_by_load_name 434 435self.assert_(X.passed) 436""") 437 438 def testLocalsFunction(self): 439 440 def f(x): 441 def g(y): 442 def h(z): 443 return y + z 444 w = x + y 445 y += 3 446 return locals() 447 return g 448 449 d = f(2)(4) 450 self.assert_('h' in d) 451 del d['h'] 452 self.assertEqual(d, {'x': 2, 'y': 7, 'w': 6}) 453 454 def testLocalsClass(self): 455 # This test verifies that calling locals() does not pollute 456 # the local namespace of the class with free variables. Old 457 # versions of Python had a bug, where a free variable being 458 # passed through a class namespace would be inserted into 459 # locals() by locals() or exec or a trace function. 460 # 461 # The real bug lies in frame code that copies variables 462 # between fast locals and the locals dict, e.g. when executing 463 # a trace function. 464 465 def f(x): 466 class C: 467 x = 12 468 def m(self): 469 return x 470 locals() 471 return C 472 473 self.assertEqual(f(1).x, 12) 474 475 def f(x): 476 class C: 477 y = x 478 def m(self): 479 return x 480 z = list(locals()) 481 return C 482 483 varnames = f(1).z 484 self.assert_("x" not in varnames) 485 self.assert_("y" in varnames) 486 487 def testBoundAndFree(self): 488 # var is bound and free in class 489 490 def f(x): 491 class C: 492 def m(self): 493 return x 494 a = x 495 return C 496 497 inst = f(3)() 498 self.assertEqual(inst.a, inst.m()) 499 500 def testInteractionWithTraceFunc(self): 501 502 import sys 503 def tracer(a,b,c): 504 return tracer 505 506 def adaptgetter(name, klass, getter): 507 kind, des = getter 508 if kind == 1: # AV happens when stepping from this line to next 509 if des == "": 510 des = "_%s__%s" % (klass.__name__, name) 511 return lambda obj: getattr(obj, des) 512 513 class TestClass: 514 pass 515 516 sys.settrace(tracer) 517 adaptgetter("foo", TestClass, (1, "")) 518 sys.settrace(None) 519 520 self.assertRaises(TypeError, sys.settrace) 521 522 def testEvalExecFreeVars(self): 523 524 def f(x): 525 return lambda: x + 1 526 527 g = f(3) 528 self.assertRaises(TypeError, eval, g.__code__) 529 530 try: 531 exec(g.__code__, {}) 532 except TypeError: 533 pass 534 else: 535 self.fail("exec should have failed, because code contained free vars") 536 537 def testListCompLocalVars(self): 538 539 try: 540 print(bad) 541 except NameError: 542 pass 543 else: 544 print("bad should not be defined") 545 546 def x(): 547 [bad for s in 'a b' for bad in s.split()] 548 549 x() 550 try: 551 print(bad) 552 except NameError: 553 pass 554 555 def testEvalFreeVars(self): 556 557 def f(x): 558 def g(): 559 x 560 eval("x + 1") 561 return g 562 563 f(4)() 564 565 def testNonLocalFunction(self): 566 567 def f(x): 568 def inc(): 569 nonlocal x 570 x += 1 571 return x 572 def dec(): 573 nonlocal x 574 x -= 1 575 return x 576 return inc, dec 577 578 inc, dec = f(0) 579 self.assertEqual(inc(), 1) 580 self.assertEqual(inc(), 2) 581 self.assertEqual(dec(), 1) 582 self.assertEqual(dec(), 0) 583 584 def testNonLocalMethod(self): 585 586 def f(x): 587 class c: 588 def inc(self): 589 nonlocal x 590 x += 1 591 return x 592 def dec(self): 593 nonlocal x 594 x -= 1 595 return x 596 return c() 597 598 c = f(0) 599 self.assertEqual(c.inc(), 1) 600 self.assertEqual(c.inc(), 2) 601 self.assertEqual(c.dec(), 1) 602 self.assertEqual(c.dec(), 0) 603 604 def testNonLocalClass(self): 605 606 def f(x): 607 class c: 608 nonlocal x 609 x += 1 610 def get(self): 611 return x 612 return c() 613 614 c = f(0) 615 self.assertEqual(c.get(), 1) 616 self.assert_("x" not in c.__class__.__dict__) 617 618 619 def testNonLocalGenerator(self): 620 621 def f(x): 622 def g(y): 623 nonlocal x 624 for i in range(y): 625 x += 1 626 yield x 627 return g 628 629 g = f(0) 630 self.assertEqual(list(g(5)), [1, 2, 3, 4, 5]) 631 632 def testNestedNonLocal(self): 633 634 def f(x): 635 def g(): 636 nonlocal x 637 x -= 2 638 def h(): 639 nonlocal x 640 x += 4 641 return x 642 return h 643 return g 644 645 g = f(1) 646 h = g() 647 self.assertEqual(h(), 3) 648 649 650def test_main(): 651 run_unittest(ScopeTests) 652 653if __name__ == '__main__': 654 test_main() 655