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