summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorJeremy Hylton <jeremy@alum.mit.edu>2007-02-26 18:41:18 (GMT)
committerJeremy Hylton <jeremy@alum.mit.edu>2007-02-26 18:41:18 (GMT)
commit759410b372915be0de2a225d7fc6b71dcfae6db3 (patch)
treee0a670017cde5e0b337ff574deae09daa9ff4c92 /Lib
parent7b7d1c8282fa2599e2f132c401defde3c9b42e3f (diff)
downloadcpython-759410b372915be0de2a225d7fc6b71dcfae6db3.zip
cpython-759410b372915be0de2a225d7fc6b71dcfae6db3.tar.gz
cpython-759410b372915be0de2a225d7fc6b71dcfae6db3.tar.bz2
Do not copy free variables to locals in class namespaces.
Fixes bug 1569356, but at the cost of a minor incompatibility in locals(). Add test that verifies that the class namespace is not polluted. Also clarify the behavior in the library docs. Along the way, cleaned up the dict_to_map and map_to_dict implementations and added some comments that explain what they do.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/test/test_scope.py33
1 files changed, 33 insertions, 0 deletions
diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py
index a53b30f..db88dbd 100644
--- a/Lib/test/test_scope.py
+++ b/Lib/test/test_scope.py
@@ -486,6 +486,39 @@ self.assert_(X.passed)
del d['h']
self.assertEqual(d, {'x': 2, 'y': 7, 'w': 6})
+ def testLocalsClass(self):
+ # This test verifies that calling locals() does not pollute
+ # the local namespace of the class with free variables. Old
+ # versions of Python had a bug, where a free variable being
+ # passed through a class namespace would be inserted into
+ # locals() by locals() or exec or a trace function.
+ #
+ # The real bug lies in frame code that copies variables
+ # between fast locals and the locals dict, e.g. when executing
+ # a trace function.
+
+ def f(x):
+ class C:
+ x = 12
+ def m(self):
+ return x
+ locals()
+ return C
+
+ self.assertEqual(f(1).x, 12)
+
+ def f(x):
+ class C:
+ y = x
+ def m(self):
+ return x
+ z = list(locals())
+ return C
+
+ varnames = f(1).z
+ self.assert_("x" not in varnames)
+ self.assert_("y" in varnames)
+
def testBoundAndFree(self):
# var is bound and free in class