]> granicus.if.org Git - python/commitdiff
Issues #13959, 14647: Re-implement imp.reload() in Lib/imp.py.
authorBrett Cannon <brett@python.org>
Sun, 29 Apr 2012 18:38:11 +0000 (14:38 -0400)
committerBrett Cannon <brett@python.org>
Sun, 29 Apr 2012 18:38:11 +0000 (14:38 -0400)
Thanks to Eric Snow for the patch.

Include/pystate.h
Lib/imp.py
Objects/moduleobject.c
Python/import.c
Python/pystate.c
Python/pythonrun.c

index 68d512bb576acbdcf72589bec74cffc6eecfb4e5..62724928f5971e343821bf3672a9fbbc5aa1a8d8 100644 (file)
@@ -26,7 +26,6 @@ typedef struct _is {
     PyObject *sysdict;
     PyObject *builtins;
     PyObject *importlib;
-    PyObject *modules_reloading;
 
     PyObject *codec_search_path;
     PyObject *codec_search_cache;
index 2abd7af0dba82a56764056ccda6662ca747b4dae..03077b6bf65d228f1598471b80ab08c3e299e294 100644 (file)
@@ -6,7 +6,7 @@ functionality over this module.
 
 """
 # (Probably) need to stay in _imp
-from _imp import (lock_held, acquire_lock, release_lock, reload,
+from _imp import (lock_held, acquire_lock, release_lock,
                   load_dynamic, get_frozen_object, is_frozen_package,
                   init_builtin, init_frozen, is_builtin, is_frozen,
                   _fix_co_filename)
@@ -207,3 +207,34 @@ def find_module(name, path=None):
             encoding = tokenize.detect_encoding(file.readline)[0]
     file = open(file_path, mode, encoding=encoding)
     return file, file_path, (suffix, mode, type_)
+
+
+_RELOADING = {}
+
+def reload(module):
+    """Reload the module and return it.
+
+    The module must have been successfully imported before.
+
+    """
+    if not module or type(module) != type(sys):
+        raise TypeError("reload() argument must be module")
+    name = module.__name__
+    if name not in sys.modules:
+        msg = "module {} not in sys.modules"
+        raise ImportError(msg.format(name), name=name)
+    if name in _RELOADING:
+        return _RELOADING[name]
+    _RELOADING[name] = module
+    try:
+        parent_name = name.rpartition('.')[0]
+        if parent_name and parent_name not in sys.modules:
+            msg = "parent {!r} not in sys.modules"
+            raise ImportError(msg.format(parentname), name=parent_name)
+        return module.__loader__.load_module(name)
+    finally:
+        try:
+            del _RELOADING[name]
+        except KeyError:
+            pass
+
index b69bce6e960de6bbae68bfc5f750885d2b6d394d..7655f157638db526ed12e238c1ce0c810d7701c8 100644 (file)
@@ -285,7 +285,7 @@ _PyModule_Clear(PyObject *m)
     pos = 0;
     while (PyDict_Next(d, &pos, &key, &value)) {
         if (value != Py_None && PyUnicode_Check(key)) {
-            if (PyUnicode_READ_CHAR(key, 0) == '_' && 
+            if (PyUnicode_READ_CHAR(key, 0) == '_' &&
                 PyUnicode_READ_CHAR(key, 1) != '_') {
                 if (Py_VerboseFlag > 1) {
                     const char *s = _PyUnicode_AsString(key);
index 0580f608fb5a2d215326786fe613c455b7dd27ec..71485bd1eaff1307d6f2cbbd1486ddc45fbc7d25 100644 (file)
@@ -410,14 +410,6 @@ _PyImport_Fini(void)
 #endif
 }
 
-static void
-imp_modules_reloading_clear(void)
-{
-    PyInterpreterState *interp = PyThreadState_Get()->interp;
-    if (interp->modules_reloading != NULL)
-        PyDict_Clear(interp->modules_reloading);
-}
-
 /* Helper for sys */
 
 PyObject *
@@ -575,7 +567,6 @@ PyImport_Cleanup(void)
     PyDict_Clear(modules);
     interp->modules = NULL;
     Py_DECREF(modules);
-    Py_CLEAR(interp->modules_reloading);
 }
 
 
@@ -1783,87 +1774,23 @@ PyImport_ImportModuleLevel(const char *name, PyObject *globals, PyObject *locals
 PyObject *
 PyImport_ReloadModule(PyObject *m)
 {
-    PyInterpreterState *interp = PyThreadState_Get()->interp;
-    PyObject *modules_reloading = interp->modules_reloading;
+    _Py_IDENTIFIER(reload);
+    PyObject *reloaded_module = NULL;
     PyObject *modules = PyImport_GetModuleDict();
-    PyObject *loader = NULL, *existing_m = NULL;
-    PyObject *name;
-    Py_ssize_t subname_start;
-    PyObject *newm = NULL;
-    _Py_IDENTIFIER(__loader__);
-    _Py_IDENTIFIER(load_module);
-
-    if (modules_reloading == NULL) {
-        Py_FatalError("PyImport_ReloadModule: "
-                      "no modules_reloading dictionary!");
-        return NULL;
-    }
-
-    if (m == NULL || !PyModule_Check(m)) {
-        PyErr_SetString(PyExc_TypeError,
-                        "reload() argument must be module");
-        return NULL;
-    }
-    name = PyModule_GetNameObject(m);
-    if (name == NULL || PyUnicode_READY(name) == -1)
-        return NULL;
-    if (m != PyDict_GetItem(modules, name)) {
-        PyErr_Format(PyExc_ImportError,
-                     "reload(): module %R not in sys.modules",
-                     name);
-        Py_DECREF(name);
-        return NULL;
-    }
-    existing_m = PyDict_GetItem(modules_reloading, name);
-    if (existing_m != NULL) {
-        /* Due to a recursive reload, this module is already
-           being reloaded. */
-        Py_DECREF(name);
-        Py_INCREF(existing_m);
-        return existing_m;
-    }
-    if (PyDict_SetItem(modules_reloading, name, m) < 0) {
-        Py_DECREF(name);
-        return NULL;
-    }
-
-    subname_start = PyUnicode_FindChar(name, '.', 0,
-                                       PyUnicode_GET_LENGTH(name), -1);
-    if (subname_start != -1) {
-        PyObject *parentname, *parent;
-        parentname = PyUnicode_Substring(name, 0, subname_start);
-        if (parentname == NULL) {
-            goto error;
-        }
-        parent = PyDict_GetItem(modules, parentname);
-        Py_XDECREF(parent);
-        if (parent == NULL) {
-            PyErr_Format(PyExc_ImportError,
-                "reload(): parent %R not in sys.modules",
-                 parentname);
-            goto error;
+    PyObject *imp = PyDict_GetItemString(modules, "imp");
+    if (imp == NULL) {
+        imp = PyImport_ImportModule("imp");
+        if (imp == NULL) {
+            return NULL;
         }
     }
-
-    loader = _PyObject_GetAttrId(m, &PyId___loader__);
-    if (loader == NULL) {
-        goto error;
-    }
-    newm = _PyObject_CallMethodId(loader, &PyId_load_module, "O", name);
-    Py_DECREF(loader);
-    if (newm == NULL) {
-        /* load_module probably removed name from modules because of
-         * the error.  Put back the original module object.  We're
-         * going to return NULL in this case regardless of whether
-         * replacing name succeeds, so the return value is ignored.
-         */
-        PyDict_SetItem(modules, name, m);
+    else {
+        Py_INCREF(imp);
     }
 
-error:
-    imp_modules_reloading_clear();
-    Py_DECREF(name);
-    return newm;
+    reloaded_module = _PyObject_CallMethodId(imp, &PyId_reload, "O", m);
+    Py_DECREF(imp);
+    return reloaded_module;
 }
 
 
@@ -2160,17 +2087,6 @@ imp_load_dynamic(PyObject *self, PyObject *args)
 
 #endif /* HAVE_DYNAMIC_LOADING */
 
-static PyObject *
-imp_reload(PyObject *self, PyObject *v)
-{
-    return PyImport_ReloadModule(v);
-}
-
-PyDoc_STRVAR(doc_reload,
-"reload(module) -> module\n\
-\n\
-Reload the module.  The module must have been successfully imported before.");
-
 
 /* Doc strings */
 
@@ -2214,7 +2130,6 @@ static PyMethodDef imp_methods[] = {
     {"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},
-    {"reload",       imp_reload,       METH_O,       doc_reload},
     {"get_frozen_object",       imp_get_frozen_object,  METH_VARARGS},
     {"is_frozen_package",   imp_is_frozen_package,  METH_VARARGS},
     {"init_builtin",            imp_init_builtin,       METH_VARARGS},
index fdcbbcec87ad69a14037b5943661fa1511c8d5cc..a0489ad08a2dd037f56f4847ec8a3ac40e781e5b 100644 (file)
@@ -69,7 +69,6 @@ PyInterpreterState_New(void)
             Py_FatalError("Can't initialize threads for interpreter");
 #endif
         interp->modules = NULL;
-        interp->modules_reloading = NULL;
         interp->modules_by_index = NULL;
         interp->sysdict = NULL;
         interp->builtins = NULL;
@@ -114,7 +113,6 @@ PyInterpreterState_Clear(PyInterpreterState *interp)
     Py_CLEAR(interp->codec_error_registry);
     Py_CLEAR(interp->modules);
     Py_CLEAR(interp->modules_by_index);
-    Py_CLEAR(interp->modules_reloading);
     Py_CLEAR(interp->sysdict);
     Py_CLEAR(interp->builtins);
     Py_CLEAR(interp->importlib);
index 9e20e4a051bb03aeb7e569bf88009ebd5a3ed50d..cd3cf5c53c22bb42422aae2b2652b38e48c60cbd 100644 (file)
@@ -314,9 +314,6 @@ Py_InitializeEx(int install_sigs)
     interp->modules = PyDict_New();
     if (interp->modules == NULL)
         Py_FatalError("Py_Initialize: can't make modules dictionary");
-    interp->modules_reloading = PyDict_New();
-    if (interp->modules_reloading == NULL)
-        Py_FatalError("Py_Initialize: can't make modules_reloading dictionary");
 
     /* Init Unicode implementation; relies on the codec registry */
     if (_PyUnicode_Init() < 0)
@@ -680,7 +677,6 @@ Py_NewInterpreter(void)
     /* XXX The following is lax in error checking */
 
     interp->modules = PyDict_New();
-    interp->modules_reloading = PyDict_New();
 
     bimod = _PyImport_FindBuiltin("builtins");
     if (bimod != NULL) {