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[] = {
_______________________________________________
Python-3000-checkins mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-3000-checkins

Reply via email to