[Python-3000-checkins] r59890 - in python/branches/py3k-importhook: Lib/test/test_imp.py Python/import.c

christian.heimes python-3000-checkins at python.org
Thu Jan 10 18:39:27 CET 2008


Author: christian.heimes
Date: Thu Jan 10 18:39:27 2008
New Revision: 59890

Modified:
   python/branches/py3k-importhook/Lib/test/test_imp.py
   python/branches/py3k-importhook/Python/import.c
Log:
sys.post_import_hooks[name] is set to None during and after the callbacks are called (as proposed by PJE)
imp_notify_module_loaded() is protected by the importer lock

Modified: python/branches/py3k-importhook/Lib/test/test_imp.py
==============================================================================
--- python/branches/py3k-importhook/Lib/test/test_imp.py	(original)
+++ python/branches/py3k-importhook/Lib/test/test_imp.py	Thu Jan 10 18:39:27 2008
@@ -111,8 +111,7 @@
         self.assert_("sys" in callback.mods, callback.mods)
         self.assert_(callback.mods["sys"] is sys, callback.mods)
         self.failIf("telnetlib" in callback.mods, callback.mods)
-        regc = sys.post_import_hooks.get("sys", False)
-        self.assert_(regc is False, regc)
+        self.assertEqual(sys.post_import_hooks["sys"], None)
 
     def test_register_callback_new(self):
         callback = CallBack()
@@ -129,11 +128,15 @@
         import telnetlib
         self.assert_("telnetlib" in callback.mods, callback.mods)
         self.assert_(callback.mods["telnetlib"] is telnetlib, callback.mods)
+        self.assertEqual(sys.post_import_hooks["telnetlib"], None)
 
     def test_post_import_notify(self):
         imp.notify_module_loaded(sys)
         self.failUnlessRaises(TypeError, imp.notify_module_loaded, None)
         self.failUnlessRaises(TypeError, imp.notify_module_loaded, object())
+        # Should this fail?
+        mod = imp.new_module("post_import_test_module")
+        imp.notify_module_loaded(mod)
 
 
 def test_main():

Modified: python/branches/py3k-importhook/Python/import.c
==============================================================================
--- python/branches/py3k-importhook/Python/import.c	(original)
+++ python/branches/py3k-importhook/Python/import.c	Thu Jan 10 18:39:27 2008
@@ -655,6 +655,9 @@
 	return pihr;
 }
 
+/* Notify that a module as been loaded
+ * Must be called with the import hook acquired
+ */
 PyObject *
 PyImport_NotifyModuleLoaded(PyObject *module)
 {
@@ -673,8 +676,7 @@
 	if (module == NULL) {
 		return NULL;
 	}
-
-	/* Should I allow all kinds of objects ? */
+	/* Should I allow all kinds of objects? */
 	if (!PyModule_Check(module)) {
 		PyErr_Format(PyExc_TypeError,
 			     "A module object was expected, got '%.200s'",
@@ -683,15 +685,12 @@
 	}
 
 	/* XXX check if module is in sys.modules ? */
-	registry = PyImport_GetPostImportHooks();
-	if (registry == NULL) {
+	if ((registry = PyImport_GetPostImportHooks()) == NULL) {
 		/* warn about invalid registry? */
 		PyErr_Clear();
 		return module;
 	}
-
-	mod_name = PyObject_GetAttr(module, name);
-	if (mod_name == NULL) {
+	if ((mod_name = PyObject_GetAttr(module, name)) == NULL) {
 		goto error;
 	}
 	if (!PyUnicode_Check(mod_name)) {
@@ -707,12 +706,15 @@
 		goto error;
 	}
 
-	hooks = PyDict_GetItem(registry, mod_name);
-	if (hooks == NULL) {
+	if ((hooks = PyDict_GetItem(registry, mod_name)) == NULL) {
 		/* Either no hooks are defined or they are already fired */
 		PyErr_Clear();
 		goto end;
 	}
+	Py_INCREF(hooks);
+	if (PyDict_SetItem(registry, mod_name, Py_None) < 0) {
+		goto end;
+	}
 	if (!PyList_Check(hooks)) {
 		PyErr_Format(PyExc_TypeError,
 			     "expected None or list of hooks, got '%.200s'",
@@ -721,8 +723,7 @@
 	}
 
 	/* fire hooks */
-	it = PyObject_GetIter(hooks);
-	if (it == NULL) {
+	if ((it = PyObject_GetIter(hooks)) == NULL) {
 		goto error;
 	}
 	while ((hook = PyIter_Next(it)) != NULL) {
@@ -734,16 +735,12 @@
 		Py_DECREF(o);
 	}
 
-	/* Mark hooks as fired */
-	if (PyDict_DelItem(registry, mod_name) < 0) {
-		goto error;
-	}
-
     end:
 	status = 0;
     error:
 	Py_XDECREF(mod_name);
 	Py_XDECREF(it);
+	Py_XDECREF(hooks);
 	if (status < 0) {
 		Py_XDECREF(module);
 		return NULL;
@@ -753,10 +750,13 @@
 	}
 }
 
+/* register a new hook for a module
+   PyImport_RegisterPostImportHook acquires the global import look
+ */
 PyObject *
 PyImport_RegisterPostImportHook(PyObject *callable, PyObject *mod_name)
 {
-	PyObject *registry = NULL, *hooks = NULL;
+	PyObject *registry = NULL, *hooks = NULL, *modules;
 	int status = -1, locked = 0;
 
 	if (!PyCallable_Check(callable)) {
@@ -769,7 +769,8 @@
 	}
 
 	registry = PyImport_GetPostImportHooks();
-	if (registry == NULL) {
+	modules = PyImport_GetModuleDict();
+	if (registry == NULL || modules == NULL) {
 		goto error;
 	}
 
@@ -778,43 +779,43 @@
 
 	hooks = PyDict_GetItem(registry, mod_name);
 	/* module may be already loaded, get the module object from sys */
-	if (hooks == NULL) {
-		PyObject *o, *modules;
+	if (hooks == NULL || hooks == Py_None) {
 		PyObject *module = NULL;
 
-		modules = PyImport_GetModuleDict();
-		if (modules == NULL) {
-			goto error;
-		}
-		module = PyDict_GetItem(modules, mod_name);
-		if (module != NULL) {
+		if ((module = PyDict_GetItem(modules, mod_name)) != NULL) {
 			/* module is already loaded, fire hook immediately */
+			PyObject *o;
+
 			o = PyObject_CallFunctionObjArgs(callable, module, NULL);
+			Py_XDECREF(o);
+			if (hooks == NULL) {
+				if (PyDict_SetItem(registry, mod_name, Py_None) < 0) {
+					goto error;
+				}
+			}
 			if (o == NULL) {
 				goto error;
 			}
-			Py_DECREF(o);
 			goto end;
 		}
-	}
-	/* no hook registered so far */
-	if (hooks == NULL) {
-		PyErr_Clear();
-		hooks = PyList_New(0);
-		if (hooks == NULL) {
-			goto error;
-		}
-		if (PyDict_SetItem(registry, mod_name, hooks) < 0) {
-			goto error;
+		else {
+			/* no hook has been registered so far */
+			PyErr_Clear();
+			assert(hooks != Py_None);
+			hooks = PyList_New(0);
+			if (hooks == NULL) {
+				goto error;
+			}
+			if (PyDict_SetItem(registry, mod_name, hooks) < 0) {
+				goto error;
+			}
 		}
 	}
-	else {
-		if (!PyList_Check(hooks)) {
+	if (!PyList_Check(hooks)) {
 			PyErr_Format(PyExc_TypeError,
 				     "expected list of hooks, got '%.200s'",
 				     Py_TYPE(hooks)->tp_name);
 			goto error;
-		}
 	}
 	/* append a new callable */
 	if (PyList_Append(hooks, callable) < 0) {
@@ -3212,13 +3213,20 @@
 static PyObject *
 imp_notify_module_loaded(PyObject *self, PyObject *args)
 {
-	PyObject *mod;
+	PyObject *mod, *o;
 
         if (!PyArg_ParseTuple(args, "O:notify_module_loaded", &mod))
                 return NULL;
 
 	Py_INCREF(mod);
-	return PyImport_NotifyModuleLoaded(mod);
+	lock_import();
+	o = PyImport_NotifyModuleLoaded(mod);
+	if (unlock_import() < 0) {
+		PyErr_SetString(PyExc_RuntimeError,
+				"not holding the import lock");
+		return NULL;
+	}
+	return o;
 }
 
 static PyObject *
@@ -3285,7 +3293,9 @@
 "register_post_import_hook(callable, module_name) -> None");
 
 PyDoc_STRVAR(doc_notify_module_loaded,
-"notify_module_loaded(module) -> module");
+"notify_module_loaded(module) -> module\n\
+Notifies the system that a module has been loaded. The method is\n\
+with the global import locker.");
 
 
 static PyMethodDef imp_methods[] = {


More information about the Python-3000-checkins mailing list