summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
authorRaymond Hettinger <python@rcn.com>2004-07-02 06:41:07 (GMT)
committerRaymond Hettinger <python@rcn.com>2004-07-02 06:41:07 (GMT)
commit214b1c3aaea3e83302df9ea37a37b3c7548b92b1 (patch)
tree4ddeda01308aec48c7edda3188a4aad84dc9435b /Lib/test
parent78bace7442bb89aa005950a1e37f71d4704d4cb6 (diff)
downloadcpython-214b1c3aaea3e83302df9ea37a37b3c7548b92b1.zip
cpython-214b1c3aaea3e83302df9ea37a37b3c7548b92b1.tar.gz
cpython-214b1c3aaea3e83302df9ea37a37b3c7548b92b1.tar.bz2
SF Bug #215126: Over restricted type checking on eval() function
The builtin eval() function now accepts any mapping for the locals argument. Time sensitive steps guarded by PyDict_CheckExact() to keep from slowing down the normal case. My timings so no measurable impact.
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_builtin.py56
-rw-r--r--Lib/test/test_descrtut.py10
2 files changed, 55 insertions, 11 deletions
diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
index 9aa24c2..8fea0ca 100644
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -3,7 +3,7 @@
import test.test_support, unittest
from test.test_support import fcmp, have_unicode, TESTFN, unlink
-import sys, warnings, cStringIO, random
+import sys, warnings, cStringIO, random, UserDict
warnings.filterwarnings("ignore", "hex../oct.. of negative int",
FutureWarning, __name__)
warnings.filterwarnings("ignore", "integer argument expected",
@@ -262,6 +262,60 @@ class BuiltinTest(unittest.TestCase):
self.assertRaises(TypeError, eval)
self.assertRaises(TypeError, eval, ())
+ def test_general_eval(self):
+ # Tests that general mappings can be used for the locals argument
+
+ class M:
+ "Test mapping interface versus possible calls from eval()."
+ def __getitem__(self, key):
+ if key == 'a':
+ return 12
+ raise KeyError
+ def keys(self):
+ return list('xyz')
+
+ m = M()
+ g = globals()
+ self.assertEqual(eval('a', g, m), 12)
+ self.assertRaises(NameError, eval, 'b', g, m)
+ self.assertEqual(eval('dir()', g, m), list('xyz'))
+ self.assertEqual(eval('globals()', g, m), g)
+ self.assertEqual(eval('locals()', g, m), m)
+
+ # Verify that dict subclasses work as well
+ class D(dict):
+ def __getitem__(self, key):
+ if key == 'a':
+ return 12
+ return dict.__getitem__(self, key)
+ def keys(self):
+ return list('xyz')
+
+ d = D()
+ self.assertEqual(eval('a', g, d), 12)
+ self.assertRaises(NameError, eval, 'b', g, d)
+ self.assertEqual(eval('dir()', g, d), list('xyz'))
+ self.assertEqual(eval('globals()', g, d), g)
+ self.assertEqual(eval('locals()', g, d), d)
+
+ # Verify locals stores (used by list comps)
+ eval('[locals() for i in (2,3)]', g, d)
+ eval('[locals() for i in (2,3)]', g, UserDict.UserDict())
+
+ class SpreadSheet:
+ "Sample application showing nested, calculated lookups."
+ _cells = {}
+ def __setitem__(self, key, formula):
+ self._cells[key] = formula
+ def __getitem__(self, key ):
+ return eval(self._cells[key], globals(), self)
+
+ ss = SpreadSheet()
+ ss['a1'] = '5'
+ ss['a2'] = 'a1*6'
+ ss['a3'] = 'a2*7'
+ self.assertEqual(ss['a3'], 210)
+
# Done outside of the method test_z to get the correct scope
z = 0
f = open(TESTFN, 'w')
diff --git a/Lib/test/test_descrtut.py b/Lib/test/test_descrtut.py
index 58b7451..851ce4a 100644
--- a/Lib/test/test_descrtut.py
+++ b/Lib/test/test_descrtut.py
@@ -78,16 +78,6 @@ statement or the built-in function eval():
3
>>>
-However, our __getitem__() method is not used for variable access by the
-interpreter:
-
- >>> exec "print foo" in a
- Traceback (most recent call last):
- File "<stdin>", line 1, in ?
- File "<string>", line 1, in ?
- NameError: name 'foo' is not defined
- >>>
-
Now I'll show that defaultdict instances have dynamic instance variables,
just like classic classes: