This is a multi-part message in MIME format. ------=_NextPart_000_0000_01C344A6.403D6090 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Hi python-dev, I noticed this behaviour: Python 2.3b2 (#1, Jun 30 2003, 13:04:39) [GCC 2.95.3 20010315 (release)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import sys, new >>> d = {'__builtins__':{}} >>> d['mod'] = new.module('mod') >>> d['mod'].__builtins__ = d['__builtins__'] >>> exec "mod.reload = 42" in d <string>:1: DeprecationWarning: assignment shadows builtin >>> d['sys'] = sys >>> exec "print sys._getframe().f_builtins" in d {} Surely, the DeprecationWarning shouldn't be printed if you use __builtins__ to explicitly define your own builtins dict? I mean, the 'reload' name in this case is an unknown name until it is defined in mod. I looked through the archive and found the thread which describes why this change was done, namely so that, eventually, the current builtin name checking can be moved from runtime to compile time. Shouldn't the compile time check be able to take __builtins__ into account? Assuming the answer to that is 'yes' then shouldn't the current DeprecationWarning also be able to deal with it? Looking into the code (Objects/moduleobject.c), I discovered that the code does deal with it, but since it assigns to a static variable, the builtin names are found once and then for every subsequent check, the previously calculated dict is used. However, doing this means that you get the errorenous (well, imho) warning above. And since DeprecationWarnings usually indicate that the operation will be illegal at some point, I wanted to ensure that custom builtins via __builtins__ doesn't have this error. Therefore, I submit for your approval/scorn/pointing and laughing the attached patch. It deals with the problem in a way that involves no change unless PyEval_GetBuiltins() returns a builtins dict different from PyThreadState_Get()->interp->builtin (the builtins dict should never change thus unless a custom __builtins__ is in effect as far as I can tell). In the case that a different builtins is detected, a local list of builtin names is used for that call to module_setattr(). The way the problem is solved is rather naive, I admit, but I didn't want to put any more work into it before I get confirmation from someone that I'm on the right track :-). One thing I don't understand is why the current code goes to all this trouble to create a new dict from the dict that PyEval_GetBuiltins() returns, instead of just checking directly. Ie., doing if (PyDict_GetItem(PyEval_GetBuiltins(), name) != NULL) { instead of int shadows = shadows_builtin(globals, name); if (shadows == 1) { I know that the latter will emulate a non-changable builtins dict, assuming that the first time this code is called, current_frame->f_builtins == PyThreadState_Get()->interp->builtins. As far as I can tell, this is a safe assumption. I also noticed that there's no test in Lib/test/test_module.py which verifies that shadowing builtin names raises a warning (and, indeed, that not shadowing one does not raise a warning). Is this intentional? I'm willing to write that simple test if should be there. Sorry for the long post, feel free to flog me with a wet fish ;-) Regards, Troels Therkelsen ------=_NextPart_000_0000_01C344A6.403D6090 Content-Type: application/octet-stream; name="py2.diff" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="py2.diff" Index: Objects/moduleobject.c=0A= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A= RCS file: = /var/local/cvs/python-tarball/python/dist/src/Objects/moduleobject.c,v=0A= retrieving revision 2.46=0A= diff -c -r2.46 moduleobject.c=0A= *** Objects/moduleobject.c 9 Jun 2003 18:41:54 -0000 2.46=0A= --- Objects/moduleobject.c 6 Jul 2003 23:55:58 -0000=0A= ***************=0A= *** 199,209 ****=0A= }=0A= =0A= static PyObject *=0A= ! find_builtin_names(void)=0A= {=0A= ! PyObject *builtins, *names, *key, *value;=0A= int pos =3D 0;=0A= - builtins =3D PyEval_GetBuiltins();=0A= if (builtins =3D=3D NULL || !PyDict_Check(builtins)) {=0A= PyErr_SetString(PyExc_SystemError, "no builtins dict!");=0A= return NULL;=0A= --- 199,208 ----=0A= }=0A= =0A= static PyObject *=0A= ! find_builtin_names(PyObject *builtins)=0A= {=0A= ! PyObject *names, *key, *value;=0A= int pos =3D 0;=0A= if (builtins =3D=3D NULL || !PyDict_Check(builtins)) {=0A= PyErr_SetString(PyExc_SystemError, "no builtins dict!");=0A= return NULL;=0A= ***************=0A= *** 224,247 ****=0A= return names;=0A= }=0A= =0A= /* returns 0 or 1 (and -1 on error) */=0A= static int=0A= shadows_builtin(PyObject *globals, PyObject *name)=0A= {=0A= static PyObject *builtin_names =3D NULL;=0A= ! if (builtin_names =3D=3D NULL) {=0A= ! builtin_names =3D find_builtin_names();=0A= ! if (builtin_names =3D=3D NULL)=0A= ! return -1;=0A= ! }=0A= ! if (!PyString_Check(name))=0A= return 0;=0A= ! if (PyDict_GetItem(globals, name) =3D=3D NULL &&=0A= ! PyDict_GetItem(builtin_names, name) !=3D NULL) {=0A= ! return 1;=0A= }=0A= else {=0A= ! return 0;=0A= }=0A= }=0A= =0A= --- 223,272 ----=0A= return names;=0A= }=0A= =0A= + static int=0A= + builtin_has_name(PyObject *builtins, PyObject *name)=0A= + {=0A= + PyObject *custom_builtins =3D find_builtin_names(builtins);=0A= + int ret;=0A= + =0A= + if (custom_builtins =3D=3D NULL) {=0A= + return -1;=0A= + }=0A= + =0A= + ret =3D (PyDict_GetItem(custom_builtins, name) !=3D NULL);=0A= + Py_DECREF(custom_builtins);=0A= + return ret;=0A= + }=0A= + =0A= /* returns 0 or 1 (and -1 on error) */=0A= static int=0A= shadows_builtin(PyObject *globals, PyObject *name)=0A= {=0A= static PyObject *builtin_names =3D NULL;=0A= ! PyObject *builtins =3D PyEval_GetBuiltins();=0A= ! =0A= ! if (!PyString_Check(name)=0A= ! || PyDict_GetItem(globals, name) !=3D NULL=0A= ! || builtins =3D=3D globals) {=0A= return 0;=0A= ! }=0A= ! =0A= ! if (builtins =3D=3D PyThreadState_Get()->interp->builtins) {=0A= ! if (builtin_names =3D=3D NULL) {=0A= ! builtin_names =3D find_builtin_names(builtins);=0A= ! if (builtin_names =3D=3D NULL) {=0A= ! return -1;=0A= ! }=0A= ! }=0A= ! if (PyDict_GetItem(builtin_names, name) !=3D NULL) {=0A= ! return 1;=0A= ! }=0A= ! else {=0A= ! return 0;=0A= ! }=0A= }=0A= else {=0A= ! return builtin_has_name(builtins, name);=0A= }=0A= }=0A= =0A= ***************=0A= *** 249,256 ****=0A= module_setattr(PyObject *m, PyObject *name, PyObject *value)=0A= {=0A= PyObject *globals =3D ((PyModuleObject *)m)->md_dict;=0A= ! PyObject *builtins =3D PyEval_GetBuiltins();=0A= ! if (globals !=3D NULL && globals !=3D builtins) {=0A= int shadows =3D shadows_builtin(globals, name);=0A= if (shadows =3D=3D 1) {=0A= if (PyErr_Warn(PyExc_DeprecationWarning,=0A= --- 274,280 ----=0A= module_setattr(PyObject *m, PyObject *name, PyObject *value)=0A= {=0A= PyObject *globals =3D ((PyModuleObject *)m)->md_dict;=0A= ! if (globals !=3D NULL) {=0A= int shadows =3D shadows_builtin(globals, name);=0A= if (shadows =3D=3D 1) {=0A= if (PyErr_Warn(PyExc_DeprecationWarning,=0A= ------=_NextPart_000_0000_01C344A6.403D6090--
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4