Author: christian.heimes
Date: Mon Jan 14 00:14:07 2008
New Revision: 59941

Modified:
   python/branches/py3k-importhook/Lib/test/test_imp.py
   python/branches/py3k-importhook/Python/import.c
Log:
Implemented a queue for registrations. It's filled while hooks are processed

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        Mon Jan 14 
00:14:07 2008
@@ -105,20 +105,29 @@
 import imp
 
 def callback(mod):
-    imp.test_callbacks.append(("pih_test%s", mod.__name__))
+    info = ("pih_test%(info)s", mod.__name__)
+    imp.test_callbacks.append(info)
+
+def callback_added(mod):
+    info = ("ADDED in pih_test%(info)s", mod.__name__)
+    imp.test_callbacks.append(info)
+
+def callback_add(mod):
+    callback(mod)
+    imp.register_post_import_hook(callback_added, "pih_test.a")
 
 imp.register_post_import_hook(callback, "pih_test")
-imp.register_post_import_hook(callback, "pih_test.a")
+imp.register_post_import_hook(callback_add, "pih_test.a")
 imp.register_post_import_hook(callback, "pih_test.a.b")
 """
 
 hier_withregister = [
     ("pih_test", None),
-    ("pih_test __init__", mod_callback % ''),
+    ("pih_test __init__", mod_callback % {'info':''}),
     ("pih_test a", None),
-    ("pih_test a __init__", mod_callback % '.a'),
+    ("pih_test a __init__", mod_callback % {'info':'.a'}),
     ("pih_test a b", None),
-    ("pih_test a b __init__", mod_callback % '.a.b'),
+    ("pih_test a b __init__", mod_callback % {'info':'.a.b'}),
 ]
 
 class CallBack:
@@ -240,11 +249,12 @@
         self.assertEqual(callback.names,
                          ["pih_test", "pih_test.a", "pih_test.a.b"])
 
-    def test_hook_hirarchie(self):
+    def test_hook_hirarchie_withregister(self):
         self.tmpdir = mkhier(hier_withregister)
 
         def callback(mod):
-            imp.test_callbacks.append(('', mod.__name__))
+            info = ('', mod.__name__)
+            imp.test_callbacks.append(info)
 
         imp.register_post_import_hook(callback, "pih_test")
         imp.register_post_import_hook(callback, "pih_test.a")
@@ -263,11 +273,16 @@
         expected.append(("", "pih_test.a"))
         expected.append(("pih_test", "pih_test.a"))
         expected.append(("pih_test.a", "pih_test.a"))
+        # delayed
+        expected.append(("ADDED in pih_test", "pih_test.a"))
+        expected.append(("ADDED in pih_test.a", "pih_test.a"))
         self.assertEqual(imp.test_callbacks, expected)
 
         import pih_test.a.b
         expected.append(("pih_test.a.b", "pih_test"))
         expected.append(("pih_test.a.b", "pih_test.a"))
+        # This one is called immediately because pih_test.a is already laoded
+        expected.append(("ADDED in pih_test.a.b", "pih_test.a"))
         expected.append(("", "pih_test.a.b"))
         expected.append(("pih_test", "pih_test.a.b"))
         expected.append(("pih_test.a", "pih_test.a.b"))

Modified: python/branches/py3k-importhook/Python/import.c
==============================================================================
--- python/branches/py3k-importhook/Python/import.c     (original)
+++ python/branches/py3k-importhook/Python/import.c     Mon Jan 14 00:14:07 2008
@@ -111,6 +111,14 @@
        {0, 0}
 };
 
+/* Queue for the post import hook system */
+static PyObject *register_queue = NULL;
+static int notification_in_progress = 0;
+
+static PyObject *notify_byname(const char *);
+static int queue_registration(PyObject *, PyObject *);
+static int process_registration_queue(void);
+
 
 /* Initialize things */
 
@@ -241,8 +249,8 @@
 void
 _PyImport_Fini(void)
 {
-       Py_XDECREF(extensions);
-       extensions = NULL;
+       Py_CLEAR(extensions);
+       Py_CLEAR(register_queue);
        PyMem_DEL(_PyImport_Filetab);
        _PyImport_Filetab = NULL;
 }
@@ -639,7 +647,10 @@
                              "sys.modules failed");
 }
 
-/* post import hook API */
+/* **************************************************************************
+ * post import hook API
+ */
+
 PyObject *
 PyImport_GetPostImportHooks(void)
 {
@@ -732,6 +743,8 @@
        if ((it = PyObject_GetIter(hooks)) == NULL) {
                goto error;
        }
+       
+       notification_in_progress = 1;
        while ((hook = PyIter_Next(it)) != NULL) {
                o = PyObject_CallFunctionObjArgs(hook, module, NULL);
                Py_DECREF(hook);
@@ -750,6 +763,11 @@
        if (PyDict_SetItem(registry, mod_name, Py_None) < 0) {
                status = -1;
        }
+       notification_in_progress = 0;
+       /* register queued hooks */
+       if (process_registration_queue()) {
+               goto removehooks;
+       }
     error:
        Py_XDECREF(mod_name);
        Py_XDECREF(it);
@@ -832,6 +850,13 @@
                goto error;
        }
 
+       if (notification_in_progress) {
+               if (queue_registration(callable, mod_name) != 0) {
+                       return NULL;
+               }
+               Py_RETURN_NONE;
+       }
+
        registry = PyImport_GetPostImportHooks();
        modules = PyImport_GetModuleDict();
        if (registry == NULL || modules == NULL) {
@@ -846,8 +871,9 @@
        /* module may be already loaded, get the module object from sys */
        if (hooks == NULL || hooks == Py_None) {
                PyObject *module = NULL;
-
-               if ((module = PyDict_GetItem(modules, mod_name)) != NULL) {
+               
+               module = PyDict_GetItem(modules, mod_name);
+               if (module != NULL) {
                        /* module is already loaded, fire hook immediately */
                        PyObject *o;
 
@@ -904,6 +930,84 @@
        }
 }
 
+static int
+queue_registration(PyObject *callable, PyObject *mod_name)
+{
+       
+       PyObject *tup;
+
+       if (register_queue == NULL) {
+               register_queue = PyList_New(0);
+               if (register_queue == NULL)
+                       return -1;
+       }
+       assert(notification_in_progress);
+       tup = PyTuple_New(2);
+       if (tup == NULL) {
+               return -1;
+       }
+       Py_INCREF(callable);
+       Py_INCREF(mod_name);
+       PyTuple_SetItem(tup, 0, callable);
+       PyTuple_SetItem(tup, 1, mod_name);
+       if (PyList_Append(register_queue, tup)) {
+               Py_DECREF(tup);
+               return -1;
+       }
+       Py_DECREF(tup);
+       return 0;
+}
+
+static int
+process_registration_queue(void)
+{
+       PyObject *modules;
+       PyObject *mod_name, *hook, *module, *o;
+       PyObject *it = NULL, *tup = NULL;
+       int rc = -1;
+
+       if (notification_in_progress)
+               return 0;
+
+       if (register_queue == NULL || PyList_Size(register_queue) == 0) {
+               return 0;
+       }
+
+       if ((modules = PyImport_GetModuleDict()) == NULL) {
+               goto error;
+       }
+
+       while (Py_SIZE(register_queue)) {
+               tup = PyObject_CallMethod(register_queue, "pop", "i", 0);
+               if ((hook = PyTuple_GetItem(tup, 0)) == NULL) {
+                       goto error;
+               }
+               if ((mod_name = PyTuple_GetItem(tup, 1)) == NULL) {
+                       goto error;
+               }
+               if ((module = PyDict_GetItem(modules, mod_name)) == NULL) {
+                       goto error;
+               }
+               o = PyImport_RegisterPostImportHook(hook, mod_name);
+               if (o == NULL) {
+                       goto error;
+               }
+               Py_DECREF(o);
+               Py_CLEAR(tup);
+       }
+       if (PyErr_Occurred()) {
+               goto error;
+       }
+
+       rc = 0;
+    error:
+       Py_XDECREF(it);
+       Py_XDECREF(tup);
+       return rc;
+}
+
+/* end of post import hook */
+
 static PyObject * get_sourcefile(const char *file);
 
 /* Execute a code object in a module and return the module object
_______________________________________________
Python-3000-checkins mailing list
Python-3000-checkins@python.org
http://mail.python.org/mailman/listinfo/python-3000-checkins

Reply via email to