|
3 | 3 | import test.test_support, unittest |
4 | 4 | from test.test_support import fcmp, have_unicode, TESTFN, unlink |
5 | 5 |
|
6 | | -import sys, warnings, cStringIO, random |
| 6 | +import sys, warnings, cStringIO, random, UserDict |
7 | 7 | warnings.filterwarnings("ignore", "hex../oct.. of negative int", |
8 | 8 | FutureWarning, __name__) |
9 | 9 | warnings.filterwarnings("ignore", "integer argument expected", |
@@ -262,6 +262,60 @@ def test_eval(self): |
262 | 262 | self.assertRaises(TypeError, eval) |
263 | 263 | self.assertRaises(TypeError, eval, ()) |
264 | 264 |
|
| 265 | + def test_general_eval(self): |
| 266 | + # Tests that general mappings can be used for the locals argument |
| 267 | + |
| 268 | + class M: |
| 269 | + "Test mapping interface versus possible calls from eval()." |
| 270 | + def __getitem__(self, key): |
| 271 | + if key == 'a': |
| 272 | + return 12 |
| 273 | + raise KeyError |
| 274 | + def keys(self): |
| 275 | + return list('xyz') |
| 276 | + |
| 277 | + m = M() |
| 278 | + g = globals() |
| 279 | + self.assertEqual(eval('a', g, m), 12) |
| 280 | + self.assertRaises(NameError, eval, 'b', g, m) |
| 281 | + self.assertEqual(eval('dir()', g, m), list('xyz')) |
| 282 | + self.assertEqual(eval('globals()', g, m), g) |
| 283 | + self.assertEqual(eval('locals()', g, m), m) |
| 284 | + |
| 285 | + # Verify that dict subclasses work as well |
| 286 | + class D(dict): |
| 287 | + def __getitem__(self, key): |
| 288 | + if key == 'a': |
| 289 | + return 12 |
| 290 | + return dict.__getitem__(self, key) |
| 291 | + def keys(self): |
| 292 | + return list('xyz') |
| 293 | + |
| 294 | + d = D() |
| 295 | + self.assertEqual(eval('a', g, d), 12) |
| 296 | + self.assertRaises(NameError, eval, 'b', g, d) |
| 297 | + self.assertEqual(eval('dir()', g, d), list('xyz')) |
| 298 | + self.assertEqual(eval('globals()', g, d), g) |
| 299 | + self.assertEqual(eval('locals()', g, d), d) |
| 300 | + |
| 301 | + # Verify locals stores (used by list comps) |
| 302 | + eval('[locals() for i in (2,3)]', g, d) |
| 303 | + eval('[locals() for i in (2,3)]', g, UserDict.UserDict()) |
| 304 | + |
| 305 | + class SpreadSheet: |
| 306 | + "Sample application showing nested, calculated lookups." |
| 307 | + _cells = {} |
| 308 | + def __setitem__(self, key, formula): |
| 309 | + self._cells[key] = formula |
| 310 | + def __getitem__(self, key ): |
| 311 | + return eval(self._cells[key], globals(), self) |
| 312 | + |
| 313 | + ss = SpreadSheet() |
| 314 | + ss['a1'] = '5' |
| 315 | + ss['a2'] = 'a1*6' |
| 316 | + ss['a3'] = 'a2*7' |
| 317 | + self.assertEqual(ss['a3'], 210) |
| 318 | + |
265 | 319 | # Done outside of the method test_z to get the correct scope |
266 | 320 | z = 0 |
267 | 321 | f = open(TESTFN, 'w') |
|
0 commit comments