Christian Heimes added the comment:

Updates:
* Some minor cleanups
* First draft of lazy modules implemented in C. It works but it needs
some cleanup and more error checking.

----------
keywords: +patch
title: First draft of a post import hook -> [Patch] Working post import hook 
and lazy modules
Added file: http://bugs.python.org/file8928/py3k_post_import_hook_lazy.patch

__________________________________
Tracker <[EMAIL PROTECTED]>
<http://bugs.python.org/issue1576>
__________________________________
Index: Python/import.c
===================================================================
--- Python/import.c	(Revision 59470)
+++ Python/import.c	(Arbeitskopie)
@@ -161,7 +161,7 @@
 void
 _PyImportHooks_Init(void)
 {
-	PyObject *v, *path_hooks = NULL, *zimpimport;
+	PyObject *v, *path_hooks = NULL, *zimpimport, *pihr;
 	int err = 0;
 
 	/* adding sys.path_hooks and sys.path_importer_cache, setting up
@@ -198,6 +198,14 @@
 			      );
 	}
 
+	pihr = PyDict_New();
+	if (pihr == NULL ||
+            PySys_SetObject("post_import_hooks", pihr) != 0) {
+		PyErr_Print();
+		Py_FatalError("initialization of post import hook registry "
+			      "failed");
+	}
+
 	zimpimport = PyImport_ImportModule("zipimport");
 	if (zimpimport == NULL) {
 		PyErr_Clear(); /* No zip import module -- okay */
@@ -369,6 +377,7 @@
 	"path", "argv", "ps1", "ps2",
 	"last_type", "last_value", "last_traceback",
 	"path_hooks", "path_importer_cache", "meta_path",
+	"post_import_hooks",
 	NULL
 };
 
@@ -623,6 +632,228 @@
 			      "sys.modules failed");
 }
 
+/* post import hook API */
+PyObject *
+PyImport_GetPostImportHooks(void)
+{
+	PyObject *pihr;
+
+	pihr = PySys_GetObject("post_import_hooks");
+	/* This should only happen during initialization */
+	if (pihr == NULL)
+		return NULL;
+
+	if (!PyDict_Check(pihr)) {
+		PyErr_SetString(PyExc_TypeError,
+				"post import registry is not a dict");
+	}
+	return pihr;
+}
+
+PyObject *
+PyImport_NotifyPostImport(PyObject *module)
+{
+	static PyObject *name = NULL;
+	PyObject *mod_name = NULL, *registry = NULL, *o;
+	PyObject *hooks = NULL, *hook, *it = NULL;
+	int status = -1;
+
+	if (name == NULL) {
+		name = PyUnicode_InternFromString("__name__");
+		if (name == NULL) {
+			return NULL;
+		}
+	}
+
+	if (module == NULL) {
+		return NULL;
+	}
+
+	if (!PyModule_Check(module)) {
+		PyErr_Format(PyExc_TypeError,
+			     "A module object was expected, got '%.200s'",
+			     Py_Type(module)->tp_name);
+		Py_DECREF(module);
+		return NULL;
+	}
+
+	if (PyModule_IsLazy(module)) {
+		/* nothing to do here */
+		return module;
+	}
+	/* XXX check if module is in sys.modules ? */
+
+	registry = PyImport_GetPostImportHooks();
+	if (registry == NULL) {
+		/* This should only happen during initialization */
+		return module;
+	}
+
+	mod_name = PyObject_GetAttr(module, name);
+	if (mod_name == NULL) {
+		goto error;
+	}
+	if (!PyUnicode_Check(mod_name)) {
+		PyObject *repr;
+		char *name;
+
+		repr = PyObject_Repr(module);
+		name = repr ? PyUnicode_AsString(repr) : "<unknown>";
+		PyErr_Format(PyExc_TypeError,
+			     "Module __name__ attribute of '%.200s' is not "
+			     "string", name);
+		Py_XDECREF(repr);
+		goto error;
+	}
+
+	hooks = PyDict_GetItem(registry, mod_name);
+	if (hooks == NULL || hooks == Py_None) {
+		/* Either no hooks are defined or they are already fired */
+		if (hooks == NULL) {
+			PyErr_Clear();
+		}
+		goto end;
+	}
+	if (!PyList_Check(hooks)) {
+		PyErr_Format(PyExc_TypeError,
+			     "expected None or list of hooks, got '%.200s'",
+			     Py_Type(hooks)->tp_name);
+		goto error;
+	}
+
+	/* fire hooks */
+	it = PyObject_GetIter(hooks);
+	if (it == NULL) {
+		goto error;
+	}
+	while ((hook = PyIter_Next(it)) != NULL) {
+		o = PyObject_CallFunctionObjArgs(hook, module, NULL);
+		Py_DECREF(hook);
+		if (o == NULL) {
+			goto error;
+		}
+		Py_DECREF(o);
+	}
+
+	/* Mark hooks as fired */
+	if (PyDict_SetItem(registry, mod_name, Py_None) < 0) {
+		goto error;
+	}
+
+    end:
+	status = 0;
+    error:
+	Py_XDECREF(mod_name);
+	Py_XDECREF(it);
+	if (status < 0) {
+		return NULL;
+	}
+	else {
+		return module;
+	}
+}
+
+PyObject *
+PyImport_RegisterPostImportHook(PyObject *callable, PyObject *mod_name)
+{
+	PyObject *registry = NULL, *hooks = NULL;
+	int status = -1;
+
+	if (!PyCallable_Check(callable)) {
+		PyErr_SetString(PyExc_TypeError, "expected callable");
+		goto error;
+	}
+	if (!PyUnicode_Check(mod_name)) {
+		PyErr_SetString(PyExc_TypeError, "expected string");
+		goto error;
+	}
+
+	registry = PyImport_GetPostImportHooks();
+	if (registry == NULL) {
+		goto error;
+	}
+
+	lock_import();
+
+	hooks = PyDict_GetItem(registry, mod_name);
+	/* module may be already loaded, get the module object from sys */
+	if (hooks == NULL || hooks == Py_None) {
+		PyObject *o, *modules;
+		PyObject *module = NULL;
+
+		modules = PyImport_GetModuleDict();
+		if (modules == NULL) {
+			goto error;
+		}
+		module = PyObject_GetItem(modules, mod_name);
+		if (module == NULL) {
+			PyErr_Clear();
+			/* somebody messed up sys.modules */
+			if (hooks == Py_None) {
+				; /* XXX error */
+			}
+		}
+		/* mark hooks as fired */
+		if (hooks == NULL) {
+			if (PyDict_SetItem(registry, mod_name, Py_None) < 0) {
+				goto error;
+			}
+		}
+		/* module is already loaded, fire hook immediately */
+		if (module != NULL) {
+			o = PyObject_CallFunctionObjArgs(callable, module, NULL);
+			Py_DECREF(module);
+			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 {
+             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) {
+		goto error;
+	}
+
+    end:
+	status = 0;
+    error:
+	Py_XDECREF(callable);
+	Py_XDECREF(hooks);
+	Py_XDECREF(mod_name);
+	if (unlock_import() < 0) {
+		PyErr_SetString(PyExc_RuntimeError,
+				"not holding the import lock");
+		return NULL;
+	}
+	if (status < 0) {
+		return NULL;
+	}
+	else {
+		Py_RETURN_NONE;
+	}
+}
+
 /* Execute a code object in a module and return the module object
  * WITH INCREMENTED REFERENCE COUNT.  If an error occurs, name is
  * removed from sys.modules, to avoid leaving damaged module objects
@@ -1040,7 +1271,23 @@
 	return 0;
 }
 
+static int
+is_lazy(char *name)
+{
+	PyObject *modules, *module;
 
+	modules = PyImport_GetModuleDict();
+	if (modules == NULL) {
+		return -1;
+	}
+	module = PyDict_GetItemString(modules, name);
+	if (module == NULL) {
+		return -1;
+	}
+	return PyModule_IsLazy(module);
+}
+
+
 /* Return an importer object for a sys.path/pkg.__path__ item 'p',
    possibly by fetching it from the path_importer_cache dict. If it
    wasn't yet cached, traverse path_hooks until a hook is found
@@ -1964,33 +2211,14 @@
 	return tail;
 }
 
-/* For DLL compatibility */
-#undef PyImport_ImportModuleEx
 PyObject *
-PyImport_ImportModuleEx(char *name, PyObject *globals, PyObject *locals,
-			PyObject *fromlist)
-{
-	PyObject *result;
-	lock_import();
-	result = import_module_level(name, globals, locals, fromlist, -1);
-	if (unlock_import() < 0) {
-		Py_XDECREF(result);
-		PyErr_SetString(PyExc_RuntimeError,
-				"not holding the import lock");
-		return NULL;
-	}
-	return result;
-}
-#define PyImport_ImportModuleEx(n, g, l, f) \
-	PyImport_ImportModuleLevel(n, g, l, f, -1);
-
-PyObject *
 PyImport_ImportModuleLevel(char *name, PyObject *globals, PyObject *locals,
 			 PyObject *fromlist, int level)
 {
 	PyObject *result;
 	lock_import();
 	result = import_module_level(name, globals, locals, fromlist, level);
+	result = PyImport_NotifyPostImport(result);
 	if (unlock_import() < 0) {
 		Py_XDECREF(result);
 		PyErr_SetString(PyExc_RuntimeError,
@@ -2761,6 +2989,22 @@
 	return PyBool_FromLong((long) (p == NULL ? 0 : p->size));
 }
 
+static PyObject *
+imp_is_lazy(PyObject *self, PyObject *args)
+{
+	char *name;
+	PyObject *mod;
+	
+	if (PyArg_ParseTuple(args, "s:is_lazy", &name)) {
+		return PyBool_FromLong(is_lazy(name));
+	}
+	PyErr_Clear();
+	if (!PyArg_ParseTuple(args, "O!:is_lazy", &PyModule_Type, &mod)) {
+		return NULL;
+	}
+	return PyBool_FromLong(PyModule_IsLazy(mod));
+}
+
 static FILE *
 get_file(char *pathname, PyObject *fob, char *mode)
 {
@@ -2902,6 +3146,60 @@
 	return PyModule_New(name);
 }
 
+static PyObject *
+imp_new_lazy_module(PyObject *self, PyObject *args)
+{
+	char *name;
+	if (!PyArg_ParseTuple(args, "s:new_module", &name))
+		return NULL;
+	return PyModule_NewLazy(name, 1);
+}
+
+static PyObject *
+imp_import_lazy(PyObject *self, PyObject *args)
+{
+	char *name;
+	PyObject *mod;
+	if (!PyArg_ParseTuple(args, "s:new_module", &name))
+		return NULL;
+	mod = PyModule_NewLazy(name, 1);
+	if (mod != NULL) {
+		PyObject *modules;
+
+		modules = PyImport_GetModuleDict();
+		if (modules == NULL)
+			return NULL;
+		if (PyDict_SetItemString(modules, name, mod) < 0)
+			return NULL;
+	}
+	return mod;
+}
+
+static PyObject *
+imp_register_post_import_hook(PyObject *self, PyObject *args)
+{
+	PyObject *callable, *mod_name;
+	
+	if (!PyArg_ParseTuple(args, "OO:register_post_import_hook",
+			      &callable, &mod_name))
+		return NULL;
+	Py_INCREF(callable);
+	Py_INCREF(mod_name);
+	return PyImport_RegisterPostImportHook(callable, mod_name);
+}
+
+static PyObject *
+imp_post_import_notify(PyObject *self, PyObject *args)
+{
+	PyObject *mod;
+
+        if (!PyArg_ParseTuple(args, "O:post_import_notify", &mod))
+                return NULL;
+
+	Py_INCREF(mod);
+	return PyImport_NotifyPostImport(mod);
+}
+
 /* Doc strings */
 
 PyDoc_STRVAR(doc_imp,
@@ -2951,15 +3249,37 @@
 Release the interpreter's import lock.\n\
 On platforms without threads, this function does nothing.");
 
+PyDoc_STRVAR(doc_register_post_import_hook,
+"register_post_import_hook(callable, module_name) -> None");
+
+PyDoc_STRVAR(doc_post_import_notify,
+"post_import_notify(module) -> None");
+
+PyDoc_STRVAR(doc_is_lazy,
+"is_lazy(name_or_module) -> bool");
+
+PyDoc_STRVAR(doc_new_lazy_module,
+"imp_new_lazy(name) -> lazy module");
+
+PyDoc_STRVAR(doc_import_lazy,
+"imp_new_lazy(name) -> lazy module");
+
 static PyMethodDef imp_methods[] = {
 	{"find_module",	 imp_find_module,  METH_VARARGS, doc_find_module},
 	{"get_magic",	 imp_get_magic,	   METH_NOARGS,  doc_get_magic},
 	{"get_suffixes", imp_get_suffixes, METH_NOARGS,  doc_get_suffixes},
+	{"is_lazy",      imp_is_lazy,      METH_VARARGS, doc_is_lazy},
+	{"import_lazy",  imp_import_lazy,  METH_VARARGS, doc_import_lazy},
 	{"load_module",	 imp_load_module,  METH_VARARGS, doc_load_module},
 	{"new_module",	 imp_new_module,   METH_VARARGS, doc_new_module},
+	{"new_lazy_module", imp_new_lazy_module,   METH_VARARGS, doc_new_lazy_module},
 	{"lock_held",	 imp_lock_held,	   METH_NOARGS,  doc_lock_held},
 	{"acquire_lock", imp_acquire_lock, METH_NOARGS,  doc_acquire_lock},
 	{"release_lock", imp_release_lock, METH_NOARGS,  doc_release_lock},
+	{"register_post_import_hook",	imp_register_post_import_hook,
+		METH_VARARGS, doc_register_post_import_hook},
+	{"post_import_notify", imp_post_import_notify, METH_VARARGS,
+		doc_post_import_notify},
 	/* The rest are obsolete */
 	{"get_frozen_object",	imp_get_frozen_object,	METH_VARARGS},
 	{"init_builtin",	imp_init_builtin,	METH_VARARGS},
Index: Include/moduleobject.h
===================================================================
--- Include/moduleobject.h	(Revision 59470)
+++ Include/moduleobject.h	(Arbeitskopie)
@@ -13,9 +13,11 @@
 #define PyModule_CheckExact(op) (Py_Type(op) == &PyModule_Type)
 
 PyAPI_FUNC(PyObject *) PyModule_New(const char *);
+PyAPI_FUNC(PyObject *) PyModule_NewLazy(const char *, int);
 PyAPI_FUNC(PyObject *) PyModule_GetDict(PyObject *);
 PyAPI_FUNC(const char *) PyModule_GetName(PyObject *);
 PyAPI_FUNC(const char *) PyModule_GetFilename(PyObject *);
+PyAPI_FUNC(int) PyModule_IsLazy(PyObject *);
 PyAPI_FUNC(void) _PyModule_Clear(PyObject *);
 
 #ifdef __cplusplus
Index: Include/import.h
===================================================================
--- Include/import.h	(Revision 59470)
+++ Include/import.h	(Arbeitskopie)
@@ -17,13 +17,6 @@
 PyAPI_FUNC(PyObject *) PyImport_ImportModuleLevel(char *name,
 	PyObject *globals, PyObject *locals, PyObject *fromlist, int level);
 
-/* For DLL compatibility */
-#undef PyImport_ImportModuleEx
-PyAPI_FUNC(PyObject *) PyImport_ImportModuleEx(
-	char *name, PyObject *globals, PyObject *locals, PyObject *fromlist);
-#define PyImport_ImportModuleEx(n, g, l, f) \
-	PyImport_ImportModuleLevel(n, g, l, f, -1)
-
 PyAPI_FUNC(PyObject *) PyImport_GetImporter(PyObject *path);
 PyAPI_FUNC(PyObject *) PyImport_Import(PyObject *name);
 PyAPI_FUNC(PyObject *) PyImport_ReloadModule(PyObject *m);
@@ -38,6 +31,12 @@
 PyAPI_FUNC(PyObject *)_PyImport_FindExtension(char *, char *);
 PyAPI_FUNC(PyObject *)_PyImport_FixupExtension(char *, char *);
 
+/* post import hook API */
+PyAPI_FUNC(PyObject *) PyImport_GetPostImportHooks(void);
+PyAPI_FUNC(PyObject *) PyImport_NotifyPostImport(PyObject *module);
+PyAPI_FUNC(PyObject *) PyImport_RegisterPostImportHook(
+	PyObject *callable, PyObject *mod_name);
+
 struct _inittab {
     char *name;
     void (*initfunc)(void);
Index: Objects/object.c
===================================================================
--- Objects/object.c	(Revision 59470)
+++ Objects/object.c	(Arbeitskopie)
@@ -191,6 +191,7 @@
 		      "%s:%i object at %p has negative ref count "
 		      "%" PY_FORMAT_SIZE_T "d",
 		      fname, lineno, op, op->ob_refcnt);
+	_PyObject_Dump(op);
 	Py_FatalError(buf);
 }
 
Index: Objects/moduleobject.c
===================================================================
--- Objects/moduleobject.c	(Revision 59470)
+++ Objects/moduleobject.c	(Arbeitskopie)
@@ -4,18 +4,27 @@
 #include "Python.h"
 #include "structmember.h"
 
+#define LAZY_MOD "__lazy_import__"
+#define PyModule_LAZY(m) (((PyModuleObject *)(m))->md_lazy)
+#define PyModule_NAME(m) (((PyModuleObject *)(m))->md_name)
+#define PyModule_DICT(m) (((PyModuleObject *)(m))->md_dict)
+
 typedef struct {
 	PyObject_HEAD
 	PyObject *md_dict;
+	PyObject *md_name;
+	int md_lazy; /* +1: loaded, 0: lazy, -1: real module for a lazy mod */
 } PyModuleObject;
 
+#define OFF(name) offsetof(PyModuleObject, name)
+
 static PyMemberDef module_members[] = {
-	{"__dict__", T_OBJECT, offsetof(PyModuleObject, md_dict), READONLY},
+	{"__dict__", T_OBJECT, OFF(md_dict), READONLY},
 	{0}
 };
 
 PyObject *
-PyModule_New(const char *name)
+PyModule_NewLazy(const char *name, int lazy)
 {
 	PyModuleObject *m;
 	PyObject *nameobj;
@@ -32,7 +41,10 @@
 		goto fail;
 	if (PyDict_SetItemString(m->md_dict, "__package__", Py_None) != 0)
 		goto fail;
-	Py_DECREF(nameobj);
+
+	m->md_name = nameobj; /* eat ref */
+	m->md_lazy = lazy;
+
 	PyObject_GC_Track(m);
 	return (PyObject *)m;
 
@@ -43,6 +55,12 @@
 }
 
 PyObject *
+PyModule_New(const char *name)
+{
+	return PyModule_NewLazy(name, 0);
+}
+
+PyObject *
 PyModule_GetDict(PyObject *m)
 {
 	PyObject *d;
@@ -146,6 +164,72 @@
 
 }
 
+int
+PyModule_IsLazy(PyObject *m)
+{
+	PyObject *lazy;
+	int result;
+	
+	if (!PyModule_Check(m)) {
+		PyErr_BadArgument();
+		return -1;
+	}
+	/* check struct var first */
+	if (PyModule_LAZY(m))
+		return 1;
+
+	/* fall back to module attribute for Python code */
+	lazy = PyObject_GetAttrString(m, LAZY_MOD);
+	if (lazy == NULL) {
+		PyErr_Clear();
+		return 0;
+	}
+	result =  PyObject_IsTrue(lazy);
+	Py_DECREF(lazy);
+	return result;
+}
+
+int
+PyModule_LoadLazy(PyObject *mod)
+{
+	PyObject *modules;
+	PyObject *name;
+	PyObject *realmod;
+	char *cname;
+
+	name = PyModule_NAME(mod);
+	cname = PyUnicode_AsString(name);
+	if (cname == NULL)
+		return -1;
+	modules = PyImport_GetModuleDict();
+	if (modules == NULL)
+		return -1;
+	/* remove the module from sys.modules first */
+	if (PyDict_GetItem(modules, name) != NULL) {
+		if (PyDict_DelItem(modules, name) < 0) {
+			/* XXX */
+			return -1;
+		}
+	}
+	realmod = PyImport_Import(name);
+	/* remove the real module again */
+	if (PyDict_DelItem(modules, name) < 0) {
+		/* XXX */
+		return -1;
+	}
+	Py_CLEAR(PyModule_DICT(mod));
+	Py_INCREF(PyModule_DICT(realmod));
+	PyModule_DICT(mod) = PyModule_DICT(realmod);
+	PyModule_LAZY(realmod) = -1;
+	Py_DECREF(realmod);
+	if (PyDict_SetItem(modules, name, mod) < 0) {
+		/* XXX */
+		return -1;
+	}
+	PyModule_LAZY(mod) = 0;
+	return 0;
+}
+
 /* Methods */
 
 static int
@@ -174,7 +258,8 @@
 module_dealloc(PyModuleObject *m)
 {
 	PyObject_GC_UnTrack(m);
-	if (m->md_dict != NULL) {
+	Py_CLEAR(m->md_name);
+	if (m->md_dict != NULL && PyModule_LAZY(m) == 0) {
 		_PyModule_Clear((PyObject *)m);
 		Py_DECREF(m->md_dict);
 	}
@@ -206,10 +291,45 @@
 static int
 module_traverse(PyModuleObject *m, visitproc visit, void *arg)
 {
+	Py_VISIT(m->md_name);
 	Py_VISIT(m->md_dict);
 	return 0;
 }
 
+PyObject *
+module_getattr(PyObject *obj, PyObject *name)
+{
+	//PyModuleObject *mod = (PyModuleObject*)obj;
+	if (PyModule_LAZY(obj)) {
+		char *cname;
+
+		cname = PyUnicode_AsString(name);
+		if (cname == NULL)
+			return NULL;
+		if (strcmp(cname, "__name__") == 0) {
+			Py_INCREF(PyModule_NAME(obj));
+			return PyModule_NAME(obj);
+		}
+		if (strcmp(cname, LAZY_MOD) == 0) {
+			Py_RETURN_TRUE;
+		}
+		if (PyModule_LoadLazy(obj) < 0) {
+			return NULL;
+		}
+	}
+	return PyObject_GenericGetAttr(obj, name);
+}
+
+int
+module_setattr(PyObject *obj, PyObject *name, PyObject *value)
+{
+	if (PyModule_LAZY(obj)) {
+		if (PyModule_LoadLazy(obj) < 0)
+			return -1;
+	}
+	return PyObject_GenericSetAttr(obj, name, value);
+}
+
 PyDoc_STRVAR(module_doc,
 "module(name[, doc])\n\
 \n\
@@ -233,8 +353,8 @@
 	0,					/* tp_hash */
 	0,					/* tp_call */
 	0,					/* tp_str */
-	PyObject_GenericGetAttr,		/* tp_getattro */
-	PyObject_GenericSetAttr,		/* tp_setattro */
+	module_getattr,				/* tp_getattro */
+	module_setattr,				/* tp_setattro */
 	0,					/* tp_as_buffer */
 	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
 		Py_TPFLAGS_BASETYPE,		/* tp_flags */
Index: Lib/test/test_imp.py
===================================================================
--- Lib/test/test_imp.py	(Revision 59470)
+++ Lib/test/test_imp.py	(Arbeitskopie)
@@ -1,4 +1,5 @@
 import imp
+import sys
 import thread
 import unittest
 from test import test_support
@@ -60,11 +61,86 @@
                          '"""Tokenization help for Python programs.\n')
         fp.close()
 
+def f(mod):
+    pass
 
+class CallBack:
+    def __init__(self):
+        self.mods = {}
+
+    def __call__(self, mod):
+        self.mods[mod.__name__] = mod
+        #self.spam = object()
+
+class PostImportHookTests(unittest.TestCase):
+
+    def setUp(self):
+        self.pihr = sys.post_import_hooks.copy()
+
+    def tearDown(self):
+        sys.post_import_hooks = self.pihr
+
+    def test_registry(self):
+        reg = sys.post_import_hooks
+        self.assert_(isinstance(reg, dict))
+
+    def test_register_callback_existing(self):
+        callback = CallBack()
+        imp.register_post_import_hook(callback, "sys")
+
+        # sys is already loaded and the callback is fired immediately
+        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 None, regc)
+
+    def test_register_callback_new(self):
+        callback = CallBack()
+        # an arbitrary module
+        if "telnetlib" in sys.modules:
+            del sys.modules["telnetlib"]
+        imp.register_post_import_hook(callback, "telnetlib")
+
+        regc = sys.post_import_hooks.get("telnetlib")
+        self.assert_(regc is not None, regc)
+        self.assert_(isinstance(regc, list), regc)
+        self.assert_(callback in regc, regc)
+
+        import telnetlib
+        self.assert_("telnetlib" in callback.mods, callback.mods)
+        self.assert_(callback.mods["telnetlib"] is telnetlib, callback.mods)
+
+    def test_post_import_notify(self):
+        imp.post_import_notify(sys)
+        self.failUnlessRaises(TypeError, imp.post_import_notify, None)
+        self.failUnlessRaises(TypeError, imp.post_import_notify, object())
+
+class LazyImportTests(unittest.TestCase):
+
+    def test_is_lazy(self):
+        mod = imp.new_module("lazyimporttest")
+        name = mod.__name__
+        self.assertEqual(imp.is_lazy(mod), False)
+        mod.__lazy_import__ = True
+        self.assertEqual(imp.is_lazy(mod), True)
+        mod.__lazy_import__ = False
+        self.assertEqual(imp.is_lazy(mod), False)
+
+        sys.modules[name] = mod
+        self.assertEqual(imp.is_lazy(name), False)
+        mod.__lazy_import__ = True
+        self.assertEqual(imp.is_lazy(name), True)
+        mod.__lazy_import__ = False
+        self.assertEqual(imp.is_lazy(name), False)
+        del sys.modules[name]
+
 def test_main():
     test_support.run_unittest(
                 LockTests,
                 ImportTests,
+                PostImportHookTests,
+                LazyImportTests,
             )
 
 if __name__ == "__main__":
Index: Modules/gcmodule.c
===================================================================
--- Modules/gcmodule.c	(Revision 59470)
+++ Modules/gcmodule.c	(Arbeitskopie)
@@ -269,6 +269,10 @@
 		 * generation being collected, which can be recognized
 		 * because only they have positive gc_refs.
 		 */
+#ifdef Py_DEBUG
+		if (gc->gc.gc_refs == 0)
+			_PyObject_Dump(op);
+#endif
 		assert(gc->gc.gc_refs != 0); /* else refcount was too small */
 		if (gc->gc.gc_refs > 0)
 			gc->gc.gc_refs--;
_______________________________________________
Python-bugs-list mailing list 
Unsubscribe: 
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to