Index: Include/frameobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/frameobject.h,v retrieving revision 2.37 diff -c -r2.37 frameobject.h *** Include/frameobject.h 11 Sep 2002 15:36:31 -0000 2.37 --- Include/frameobject.h 29 Jun 2004 08:33:11 -0000 *************** *** 19,25 **** PyCodeObject *f_code; /* code segment */ PyObject *f_builtins; /* builtin symbol table (PyDictObject) */ PyObject *f_globals; /* global symbol table (PyDictObject) */ ! PyObject *f_locals; /* local symbol table (PyDictObject) */ PyObject **f_valuestack; /* points after the last local */ /* Next free slot in f_valuestack. Frame creation sets to f_valuestack. Frame evaluation usually NULLs it, but a frame that yields sets it --- 19,25 ---- PyCodeObject *f_code; /* code segment */ PyObject *f_builtins; /* builtin symbol table (PyDictObject) */ PyObject *f_globals; /* global symbol table (PyDictObject) */ ! PyObject *f_locals; /* local symbol table (any mapping) */ PyObject **f_valuestack; /* points after the last local */ /* Next free slot in f_valuestack. Frame creation sets to f_valuestack. Frame evaluation usually NULLs it, but a frame that yields sets it Index: Lib/test/test_builtin.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_builtin.py,v retrieving revision 1.29 diff -c -r1.29 test_builtin.py *** Lib/test/test_builtin.py 12 Feb 2004 17:35:11 -0000 1.29 --- Lib/test/test_builtin.py 29 Jun 2004 08:33:13 -0000 *************** *** 3,9 **** import test.test_support, unittest from test.test_support import fcmp, have_unicode, TESTFN, unlink ! import sys, warnings, cStringIO, random warnings.filterwarnings("ignore", "hex../oct.. of negative int", FutureWarning, __name__) warnings.filterwarnings("ignore", "integer argument expected", --- 3,9 ---- import test.test_support, unittest from test.test_support import fcmp, have_unicode, TESTFN, unlink ! import sys, warnings, cStringIO, random, UserDict warnings.filterwarnings("ignore", "hex../oct.. of negative int", FutureWarning, __name__) warnings.filterwarnings("ignore", "integer argument expected", *************** *** 262,267 **** --- 262,321 ---- 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 + raise KeyError + 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') Index: Lib/test/test_descrtut.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_descrtut.py,v retrieving revision 1.19 diff -c -r1.19 test_descrtut.py *** Lib/test/test_descrtut.py 17 Dec 2003 20:43:32 -0000 1.19 --- Lib/test/test_descrtut.py 29 Jun 2004 08:33:13 -0000 *************** *** 78,93 **** 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 "", line 1, in ? - File "", line 1, in ? - NameError: name 'foo' is not defined - >>> - Now I'll show that defaultdict instances have dynamic instance variables, just like classic classes: --- 78,83 ---- Index: Objects/frameobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/frameobject.c,v retrieving revision 2.78 diff -c -r2.78 frameobject.c *** Objects/frameobject.c 20 Mar 2004 21:10:27 -0000 2.78 --- Objects/frameobject.c 29 Jun 2004 08:33:14 -0000 *************** *** 544,550 **** #ifdef Py_DEBUG if (code == NULL || globals == NULL || !PyDict_Check(globals) || ! (locals != NULL && !PyDict_Check(locals))) { PyErr_BadInternalCall(); return NULL; } --- 544,550 ---- #ifdef Py_DEBUG if (code == NULL || globals == NULL || !PyDict_Check(globals) || ! (locals != NULL && !PyMapping_Check(locals))) { PyErr_BadInternalCall(); return NULL; } *************** *** 688,698 **** if (deref) value = PyCell_GET(value); if (value == NULL) { ! if (PyDict_DelItem(dict, key) != 0) PyErr_Clear(); } else { ! if (PyDict_SetItem(dict, key, value) != 0) PyErr_Clear(); } } --- 688,698 ---- if (deref) value = PyCell_GET(value); if (value == NULL) { ! if (PyObject_DelItem(dict, key) != 0) PyErr_Clear(); } else { ! if (PyObject_SetItem(dict, key, value) != 0) PyErr_Clear(); } } *************** *** 705,711 **** int j; for (j = nmap; --j >= 0; ) { PyObject *key = PyTuple_GET_ITEM(map, j); ! PyObject *value = PyDict_GetItem(dict, key); if (deref) { if (value || clear) { if (PyCell_GET(values[j]) != value) { --- 705,713 ---- int j; for (j = nmap; --j >= 0; ) { PyObject *key = PyTuple_GET_ITEM(map, j); ! PyObject *value = PyObject_GetItem(dict, key); ! if (value == NULL) ! PyErr_Clear(); if (deref) { if (value || clear) { if (PyCell_GET(values[j]) != value) { *************** *** 720,725 **** --- 722,728 ---- values[j] = value; } } + Py_XDECREF(value); } } *************** *** 742,748 **** } } map = f->f_code->co_varnames; ! if (!PyDict_Check(locals) || !PyTuple_Check(map)) return; PyErr_Fetch(&error_type, &error_value, &error_traceback); fast = f->f_localsplus; --- 745,751 ---- } } map = f->f_code->co_varnames; ! if (!PyTuple_Check(map)) return; PyErr_Fetch(&error_type, &error_value, &error_traceback); fast = f->f_localsplus; *************** *** 780,786 **** map = f->f_code->co_varnames; if (locals == NULL) return; ! if (!PyDict_Check(locals) || !PyTuple_Check(map)) return; PyErr_Fetch(&error_type, &error_value, &error_traceback); fast = f->f_localsplus; --- 783,789 ---- map = f->f_code->co_varnames; if (locals == NULL) return; ! if (!PyTuple_Check(map)) return; PyErr_Fetch(&error_type, &error_value, &error_traceback); fast = f->f_localsplus; Index: Objects/object.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v retrieving revision 2.217 diff -c -r2.217 object.c *** Objects/object.c 22 Apr 2004 17:23:49 -0000 2.217 --- Objects/object.c 29 Jun 2004 08:33:14 -0000 *************** *** 1621,1627 **** PyObject *locals = PyEval_GetLocals(); if (locals == NULL) goto error; ! result = PyDict_Keys(locals); if (result == NULL) goto error; } --- 1621,1627 ---- PyObject *locals = PyEval_GetLocals(); if (locals == NULL) goto error; ! result = PyMapping_Keys(locals); if (result == NULL) goto error; } Index: Python/bltinmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/bltinmodule.c,v retrieving revision 2.309 diff -c -r2.309 bltinmodule.c *** Python/bltinmodule.c 29 Mar 2004 11:50:55 -0000 2.309 --- Python/bltinmodule.c 29 Jun 2004 08:33:15 -0000 *************** *** 455,465 **** char *str; PyCompilerFlags cf; ! if (!PyArg_ParseTuple(args, "O|O!O!:eval", &cmd, &PyDict_Type, &globals, ! &PyDict_Type, &locals)) return NULL; if (globals == Py_None) { globals = PyEval_GetGlobals(); if (locals == Py_None) --- 455,469 ---- char *str; PyCompilerFlags cf; ! if (!PyArg_ParseTuple(args, "O|O!O:eval", &cmd, &PyDict_Type, &globals, ! &locals)) return NULL; + if (locals != Py_None && !PyMapping_Check(locals)) { + PyErr_SetString(PyExc_TypeError, "locals must be a mapping"); + return NULL; + } if (globals == Py_None) { globals = PyEval_GetGlobals(); if (locals == Py_None) Index: Python/ceval.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/ceval.c,v retrieving revision 2.407 diff -c -r2.407 ceval.c *** Python/ceval.c 27 Jun 2004 15:43:12 -0000 2.407 --- Python/ceval.c 29 Jun 2004 08:33:17 -0000 *************** *** 1643,1649 **** w = GETITEM(names, oparg); v = POP(); if ((x = f->f_locals) != NULL) { ! err = PyDict_SetItem(x, w, v); Py_DECREF(v); if (err == 0) continue; break; --- 1643,1649 ---- w = GETITEM(names, oparg); v = POP(); if ((x = f->f_locals) != NULL) { ! err = PyObject_SetItem(x, w, v); Py_DECREF(v); if (err == 0) continue; break; *************** *** 1656,1662 **** case DELETE_NAME: w = GETITEM(names, oparg); if ((x = f->f_locals) != NULL) { ! if ((err = PyDict_DelItem(x, w)) != 0) format_exc_check_arg(PyExc_NameError, NAME_ERROR_MSG ,w); break; --- 1656,1662 ---- case DELETE_NAME: w = GETITEM(names, oparg); if ((x = f->f_locals) != NULL) { ! if ((err = PyObject_DelItem(x, w)) != 0) format_exc_check_arg(PyExc_NameError, NAME_ERROR_MSG ,w); break; *************** *** 1733,1746 **** case LOAD_NAME: w = GETITEM(names, oparg); ! if ((x = f->f_locals) == NULL) { PyErr_Format(PyExc_SystemError, "no locals when loading %s", PyObject_REPR(w)); break; } ! x = PyDict_GetItem(x, w); if (x == NULL) { x = PyDict_GetItem(f->f_globals, w); if (x == NULL) { x = PyDict_GetItem(f->f_builtins, w); --- 1733,1754 ---- case LOAD_NAME: w = GETITEM(names, oparg); ! if ((v = f->f_locals) == NULL) { PyErr_Format(PyExc_SystemError, "no locals when loading %s", PyObject_REPR(w)); break; } ! x = PyDict_GetItem(v, w); if (x == NULL) { + if (!PyDict_CheckExact(v)) { + x = PyObject_GetItem(v, w); + if (x != NULL) { + PUSH(x); + continue; + } + PyErr_Clear(); + } x = PyDict_GetItem(f->f_globals, w); if (x == NULL) { x = PyDict_GetItem(f->f_builtins, w);