summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorJeremy Hylton <jeremy@alum.mit.edu>2007-02-27 06:50:52 (GMT)
committerJeremy Hylton <jeremy@alum.mit.edu>2007-02-27 06:50:52 (GMT)
commit81e9502df69394821416309c7c4b5357af51f4d5 (patch)
treead38831cbebfb32890c0c57cb8b36f653300c69f /Lib
parent8b41c3dc28a16da97af50cc5f7b884db2cea7b0c (diff)
downloadcpython-81e9502df69394821416309c7c4b5357af51f4d5.zip
cpython-81e9502df69394821416309c7c4b5357af51f4d5.tar.gz
cpython-81e9502df69394821416309c7c4b5357af51f4d5.tar.bz2
Provisional implementation of PEP 3104.
Add nonlocal_stmt to Grammar and Nonlocal node to AST. They both parallel the definitions for globals. The symbol table treats variables declared as nonlocal just like variables that are free implicitly. This change is missing the language spec changes, but makes some decisions about what the spec should say via the unittests. The PEP is silent on a number of decisions, so we should review those before claiming that nonlocal is complete. Thomas Wouters made the grammer and ast changes. Jeremy Hylton added the symbol table changes and the tests. Pete Shinners and Neal Norwitz helped review the code.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/test_scope.py84
-rw-r--r--Lib/test/test_syntax.py40
2 files changed, 124 insertions, 0 deletions
diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py
index b9dc711..5fe1bc7 100644
--- a/Lib/test/test_scope.py
+++ b/Lib/test/test_scope.py
@@ -555,6 +555,90 @@ self.assert_(X.passed)
f(4)()
+ 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
+
+ inc, dec = f(0)
+ self.assertEqual(inc(), 1)
+ self.assertEqual(inc(), 2)
+ self.assertEqual(dec(), 1)
+ self.assertEqual(dec(), 0)
+
+ 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 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.assert_("x" not in 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 test_main():
run_unittest(ScopeTests)
diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py
index 8999e3a..f37b666 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -367,6 +367,46 @@ build. The number of blocks must be greater than CO_MAXBLOCKS. SF #1565514
...
SystemError: too many statically nested blocks
+Misuse of the nonlocal statement can lead to a few unique syntax errors.
+
+ >>> def f(x):
+ ... nonlocal x
+ Traceback (most recent call last):
+ ...
+ SyntaxError: name 'x' is local and nonlocal
+
+ >>> def f():
+ ... global x
+ ... nonlocal x
+ Traceback (most recent call last):
+ ...
+ SyntaxError: name 'x' is nonlocal and global
+
+ >>> def f():
+ ... nonlocal x
+ Traceback (most recent call last):
+ ...
+ SyntaxError: no binding for nonlocal 'x' found
+
+TODO(jhylton): Figure out how to test SyntaxWarning with doctest.
+
+## >>> def f(x):
+## ... def f():
+## ... print(x)
+## ... nonlocal x
+## Traceback (most recent call last):
+## ...
+## SyntaxWarning: name 'x' is assigned to before nonlocal declaration
+
+## >>> def f():
+## ... x = 1
+## ... nonlocal x
+## Traceback (most recent call last):
+## ...
+## SyntaxWarning: name 'x' is assigned to before nonlocal declaration
+
+
+
"""
import re