[Python-checkins] python/dist/src/Objects moduleobject.c,2.45,2.46

nascheme@users.sourceforge.net nascheme@users.sourceforge.net
Mon, 09 Jun 2003 11:41:56 -0700


Update of /cvsroot/python/python/dist/src/Objects
In directory sc8-pr-cvs1:/tmp/cvs-serv24960/Objects

Modified Files:
	moduleobject.c 
Log Message:
Warn about creating global variables by __setattr__ that shadow builtin
names.  Unfortunately, this is not bulletproof since the module
dictionary can be modified directly.


Index: moduleobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/moduleobject.c,v
retrieving revision 2.45
retrieving revision 2.46
diff -C2 -d -r2.45 -r2.46
*** moduleobject.c	13 Jun 2002 20:33:01 -0000	2.45
--- moduleobject.c	9 Jun 2003 18:41:54 -0000	2.46
***************
*** 199,202 ****
--- 199,267 ----
  }
  
+ static PyObject *
+ find_builtin_names(void)
+ {
+ 	PyObject *builtins, *names, *key, *value;
+ 	int pos = 0;
+ 	builtins = PyEval_GetBuiltins();
+ 	if (builtins == NULL || !PyDict_Check(builtins)) {
+   		PyErr_SetString(PyExc_SystemError, "no builtins dict!");
+ 		return NULL;
+ 	}
+ 	names = PyDict_New();
+ 	if (names == NULL)
+ 		return NULL;
+ 	while (PyDict_Next(builtins, &pos, &key, &value)) {
+ 		if (PyString_Check(key) &&
+ 				PyString_Size(key) > 0 &&
+ 				PyString_AS_STRING(key)[0] != '_') {
+ 			if (PyDict_SetItem(names, key, Py_None) < 0) {
+ 				Py_DECREF(names);
+ 				return NULL;
+ 			}
+ 		}
+ 	}
+ 	return names;
+ }
+ 
+ /* returns 0 or 1 (and -1 on error) */
+ static int
+ shadows_builtin(PyObject *globals, PyObject *name)
+ {
+ 	static PyObject *builtin_names = NULL;
+ 	if (builtin_names == NULL) {
+ 		builtin_names = find_builtin_names();
+ 		if (builtin_names == NULL)
+ 			return -1;
+ 	}
+ 	if (!PyString_Check(name))
+ 		return 0;
+ 	if (PyDict_GetItem(globals, name) == NULL &&
+ 	    PyDict_GetItem(builtin_names, name) != NULL) {
+ 		return 1;
+ 	}
+ 	else {
+ 		return 0;
+ 	}
+ }
+ 
+ static int
+ module_setattr(PyObject *m, PyObject *name, PyObject *value)
+ {
+ 	PyObject *globals = ((PyModuleObject *)m)->md_dict;
+ 	PyObject *builtins = PyEval_GetBuiltins();
+ 	if (globals != NULL && globals != builtins) {
+ 		int shadows = shadows_builtin(globals, name);
+ 		if (shadows == 1) {
+ 			if (PyErr_Warn(PyExc_DeprecationWarning,
+ 					"assignment shadows builtin") < 0)
+ 				return -1;
+ 		}
+ 		else if (shadows == -1)
+ 			return -1;
+ 	}
+ 	return PyObject_GenericSetAttr(m, name, value);
+ }
+ 
  /* We only need a traverse function, no clear function: If the module
     is in a cycle, md_dict will be cleared as well, which will break
***************
*** 235,239 ****
  	0,					/* tp_str */
  	PyObject_GenericGetAttr,		/* tp_getattro */
! 	PyObject_GenericSetAttr,		/* tp_setattro */
  	0,					/* tp_as_buffer */
  	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
--- 300,304 ----
  	0,					/* tp_str */
  	PyObject_GenericGetAttr,		/* tp_getattro */
! 	module_setattr,				/* tp_setattro */
  	0,					/* tp_as_buffer */
  	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |