summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_scope.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_scope.py')
-rw-r--r--Lib/test/test_scope.py507
1 files changed, 282 insertions, 225 deletions
diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py
index 94583e1..fbc87aa 100644
--- a/Lib/test/test_scope.py
+++ b/Lib/test/test_scope.py
@@ -1,6 +1,5 @@
import unittest
-from test.test_support import check_syntax_error, check_py3k_warnings, \
- check_warnings, run_unittest
+from test.support import check_syntax_error, run_unittest
class ScopeTests(unittest.TestCase):
@@ -164,6 +163,17 @@ class ScopeTests(unittest.TestCase):
self.assertEqual(t.method_and_var(), "method")
self.assertEqual(t.actual_global(), "global")
+ def testCellIsKwonlyArg(self):
+ # Issue 1409: Initialisation of a cell value,
+ # when it comes from a keyword-only parameter
+ def foo(*, a=17):
+ def bar():
+ return a + 5
+ return bar() + 3
+
+ self.assertEqual(foo(a=42), 50)
+ self.assertEqual(foo(), 25)
+
def testRecursion(self):
def f(x):
@@ -175,79 +185,44 @@ class ScopeTests(unittest.TestCase):
if x >= 0:
return fact(x)
else:
- raise ValueError, "x must be >= 0"
+ 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
-"""
+ check_syntax_error(self, """if 1:
+ def unoptimized_clash1(strip):
+ def f(s):
+ from sys import *
+ return getrefcount(s) # ambiguity: free or local
+ return f
+ """)
+
+ check_syntax_error(self, """if 1:
+ def unoptimized_clash2():
+ from sys import *
+ def f(s):
+ return getrefcount(s) # ambiguity: global or local
+ return f
+ """)
+
+ check_syntax_error(self, """if 1:
+ def unoptimized_clash2():
+ from sys import *
+ def g():
+ def f(s):
+ return getrefcount(s) # ambiguity: global or local
+ return f
+ """)
+
+ check_syntax_error(self, """if 1:
+ def f():
+ def g():
+ from sys import *
+ return getrefcount # global or local?
+ """)
def testLambdas(self):
@@ -276,7 +251,7 @@ def noproblem3():
def testUnboundLocal(self):
def errorInOuter():
- print y
+ print(y)
def inner():
return y
y = 1
@@ -290,18 +265,40 @@ def noproblem3():
self.assertRaises(UnboundLocalError, errorInOuter)
self.assertRaises(NameError, errorInInner)
+ def testUnboundLocal_AfterDel(self):
+ # #4617: It is now legal to delete a cell variable.
+ # The following functions must obviously compile,
+ # and give the correct error when accessing the deleted name.
+ def errorInOuter():
+ y = 1
+ del y
+ print(y)
+ def inner():
+ return y
+
+ def errorInInner():
+ def inner():
+ return y
+ y = 1
+ del y
+ inner()
+
+ self.assertRaises(UnboundLocalError, errorInOuter)
+ self.assertRaises(NameError, errorInInner)
+
+ def testUnboundLocal_AugAssign(self):
# 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}
+ exec("""if 1:
+ global_x = 1
+ def f():
+ global_x += 1
+ try:
+ f()
+ except UnboundLocalError:
+ pass
+ else:
+ fail('scope of global_x not correctly determined')
+ """, {'fail': self.fail})
def testComplexDefinitions(self):
@@ -319,99 +316,89 @@ else:
self.assertEqual(makeReturner2(a=11)()['a'], 11)
- with check_py3k_warnings(("tuple parameter unpacking has been removed",
- SyntaxWarning)):
- exec """\
-def makeAddPair((a, b)):
- def addPair((c, d)):
- return (a + c, b + d)
- return addPair
-""" in locals()
- 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)
-"""
+ # Examples posted by Samuele Pedroni to python-dev on 3/1/2001
+
+ exec("""if 1:
+ # 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):
@@ -437,28 +424,28 @@ self.assertEqual(g.get(), 13)
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)
-"""
+ exec("""if 1:
+ 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):
@@ -568,10 +555,10 @@ self.assertTrue(X.passed)
return lambda: x + 1
g = f(3)
- self.assertRaises(TypeError, eval, g.func_code)
+ self.assertRaises(TypeError, eval, g.__code__)
try:
- exec g.func_code in {}
+ exec(g.__code__, {})
except TypeError:
pass
else:
@@ -580,18 +567,18 @@ self.assertTrue(X.passed)
def testListCompLocalVars(self):
try:
- print bad
+ print(bad)
except NameError:
pass
else:
- print "bad should not be defined"
+ print("bad should not be defined")
def x():
[bad for s in 'a b' for bad in s.split()]
x()
try:
- print bad
+ print(bad)
except NameError:
pass
@@ -612,41 +599,112 @@ self.assertTrue(X.passed)
def __del__(self):
nestedcell_get()
- def f():
- global nestedcell_get
- def nestedcell_get():
- return c
+ def testNonLocalFunction(self):
+
+ def f(x):
+ def inc():
+ nonlocal x
+ x += 1
+ return x
+ def dec():
+ nonlocal x
+ x -= 1
+ return x
+ return inc, dec
- c = (Special(),)
- c = 2
+ inc, dec = f(0)
+ self.assertEqual(inc(), 1)
+ self.assertEqual(inc(), 2)
+ self.assertEqual(dec(), 1)
+ self.assertEqual(dec(), 0)
- f() # used to crash the interpreter...
+ def testNonLocalMethod(self):
+ def f(x):
+ class c:
+ def inc(self):
+ nonlocal x
+ x += 1
+ return x
+ def dec(self):
+ nonlocal x
+ x -= 1
+ return x
+ return c()
+ c = f(0)
+ self.assertEqual(c.inc(), 1)
+ self.assertEqual(c.inc(), 2)
+ self.assertEqual(c.dec(), 1)
+ self.assertEqual(c.dec(), 0)
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
+ exec("""if 1:
+ 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)
self.assertEqual(2, global_ns["result2"])
self.assertEqual(9, global_ns["result9"])
+ def testNonLocalClass(self):
+
+ def f(x):
+ class c:
+ nonlocal x
+ x += 1
+ def get(self):
+ return x
+ return c()
+
+ c = f(0)
+ self.assertEqual(c.get(), 1)
+ self.assertNotIn("x", c.__class__.__dict__)
+
+
+ def testNonLocalGenerator(self):
+
+ def f(x):
+ def g(y):
+ nonlocal x
+ for i in range(y):
+ x += 1
+ yield x
+ return g
+
+ g = f(0)
+ self.assertEqual(list(g(5)), [1, 2, 3, 4, 5])
+
+ def testNestedNonLocal(self):
+
+ def f(x):
+ def g():
+ nonlocal x
+ x -= 2
+ def h():
+ nonlocal x
+ x += 4
+ return x
+ return h
+ return g
+
+ g = f(1)
+ h = g()
+ self.assertEqual(h(), 3)
+
def testTopIsNotSignificant(self):
# See #9997.
def top(a):
@@ -655,10 +713,9 @@ result2 = h()
global a
+
def test_main():
- with check_warnings(("import \* only allowed at module level",
- SyntaxWarning)):
- run_unittest(ScopeTests)
+ run_unittest(ScopeTests)
if __name__ == '__main__':
test_main()