diff options
author | Raymond Hettinger <python@rcn.com> | 2004-07-02 06:41:07 (GMT) |
---|---|---|
committer | Raymond Hettinger <python@rcn.com> | 2004-07-02 06:41:07 (GMT) |
commit | 214b1c3aaea3e83302df9ea37a37b3c7548b92b1 (patch) | |
tree | 4ddeda01308aec48c7edda3188a4aad84dc9435b /Lib/test | |
parent | 78bace7442bb89aa005950a1e37f71d4704d4cb6 (diff) | |
download | cpython-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.py | 56 | ||||
-rw-r--r-- | Lib/test/test_descrtut.py | 10 |
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: |