Commit 62228dbd authored by Brett Cannon's avatar Brett Cannon

Issues #13959, 14647: Re-implement imp.reload() in Lib/imp.py.

Thanks to Eric Snow for the patch.
parent 1fc3ec91
...@@ -26,7 +26,6 @@ typedef struct _is { ...@@ -26,7 +26,6 @@ typedef struct _is {
PyObject *sysdict; PyObject *sysdict;
PyObject *builtins; PyObject *builtins;
PyObject *importlib; PyObject *importlib;
PyObject *modules_reloading;
PyObject *codec_search_path; PyObject *codec_search_path;
PyObject *codec_search_cache; PyObject *codec_search_cache;
......
...@@ -6,7 +6,7 @@ functionality over this module. ...@@ -6,7 +6,7 @@ functionality over this module.
""" """
# (Probably) need to stay in _imp # (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, load_dynamic, get_frozen_object, is_frozen_package,
init_builtin, init_frozen, is_builtin, is_frozen, init_builtin, init_frozen, is_builtin, is_frozen,
_fix_co_filename) _fix_co_filename)
...@@ -207,3 +207,34 @@ def find_module(name, path=None): ...@@ -207,3 +207,34 @@ def find_module(name, path=None):
encoding = tokenize.detect_encoding(file.readline)[0] encoding = tokenize.detect_encoding(file.readline)[0]
file = open(file_path, mode, encoding=encoding) file = open(file_path, mode, encoding=encoding)
return file, file_path, (suffix, mode, type_) 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
...@@ -285,7 +285,7 @@ _PyModule_Clear(PyObject *m) ...@@ -285,7 +285,7 @@ _PyModule_Clear(PyObject *m)
pos = 0; pos = 0;
while (PyDict_Next(d, &pos, &key, &value)) { while (PyDict_Next(d, &pos, &key, &value)) {
if (value != Py_None && PyUnicode_Check(key)) { if (value != Py_None && PyUnicode_Check(key)) {
if (PyUnicode_READ_CHAR(key, 0) == '_' && if (PyUnicode_READ_CHAR(key, 0) == '_' &&
PyUnicode_READ_CHAR(key, 1) != '_') { PyUnicode_READ_CHAR(key, 1) != '_') {
if (Py_VerboseFlag > 1) { if (Py_VerboseFlag > 1) {
const char *s = _PyUnicode_AsString(key); const char *s = _PyUnicode_AsString(key);
......
...@@ -410,14 +410,6 @@ _PyImport_Fini(void) ...@@ -410,14 +410,6 @@ _PyImport_Fini(void)
#endif #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 */ /* Helper for sys */
PyObject * PyObject *
...@@ -575,7 +567,6 @@ PyImport_Cleanup(void) ...@@ -575,7 +567,6 @@ PyImport_Cleanup(void)
PyDict_Clear(modules); PyDict_Clear(modules);
interp->modules = NULL; interp->modules = NULL;
Py_DECREF(modules); Py_DECREF(modules);
Py_CLEAR(interp->modules_reloading);
} }
...@@ -1783,87 +1774,23 @@ PyImport_ImportModuleLevel(const char *name, PyObject *globals, PyObject *locals ...@@ -1783,87 +1774,23 @@ PyImport_ImportModuleLevel(const char *name, PyObject *globals, PyObject *locals
PyObject * PyObject *
PyImport_ReloadModule(PyObject *m) PyImport_ReloadModule(PyObject *m)
{ {
PyInterpreterState *interp = PyThreadState_Get()->interp; _Py_IDENTIFIER(reload);
PyObject *modules_reloading = interp->modules_reloading; PyObject *reloaded_module = NULL;
PyObject *modules = PyImport_GetModuleDict(); PyObject *modules = PyImport_GetModuleDict();
PyObject *loader = NULL, *existing_m = NULL; PyObject *imp = PyDict_GetItemString(modules, "imp");
PyObject *name; if (imp == NULL) {
Py_ssize_t subname_start; imp = PyImport_ImportModule("imp");
PyObject *newm = NULL; if (imp == NULL) {
_Py_IDENTIFIER(__loader__); return NULL;
_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;
} }
} }
else {
loader = _PyObject_GetAttrId(m, &PyId___loader__); Py_INCREF(imp);
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);
} }
error: reloaded_module = _PyObject_CallMethodId(imp, &PyId_reload, "O", m);
imp_modules_reloading_clear(); Py_DECREF(imp);
Py_DECREF(name); return reloaded_module;
return newm;
} }
...@@ -2160,17 +2087,6 @@ imp_load_dynamic(PyObject *self, PyObject *args) ...@@ -2160,17 +2087,6 @@ imp_load_dynamic(PyObject *self, PyObject *args)
#endif /* HAVE_DYNAMIC_LOADING */ #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 */ /* Doc strings */
...@@ -2214,7 +2130,6 @@ static PyMethodDef imp_methods[] = { ...@@ -2214,7 +2130,6 @@ static PyMethodDef imp_methods[] = {
{"lock_held", imp_lock_held, METH_NOARGS, doc_lock_held}, {"lock_held", imp_lock_held, METH_NOARGS, doc_lock_held},
{"acquire_lock", imp_acquire_lock, METH_NOARGS, doc_acquire_lock}, {"acquire_lock", imp_acquire_lock, METH_NOARGS, doc_acquire_lock},
{"release_lock", imp_release_lock, METH_NOARGS, doc_release_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}, {"get_frozen_object", imp_get_frozen_object, METH_VARARGS},
{"is_frozen_package", imp_is_frozen_package, METH_VARARGS}, {"is_frozen_package", imp_is_frozen_package, METH_VARARGS},
{"init_builtin", imp_init_builtin, METH_VARARGS}, {"init_builtin", imp_init_builtin, METH_VARARGS},
......
...@@ -69,7 +69,6 @@ PyInterpreterState_New(void) ...@@ -69,7 +69,6 @@ PyInterpreterState_New(void)
Py_FatalError("Can't initialize threads for interpreter"); Py_FatalError("Can't initialize threads for interpreter");
#endif #endif
interp->modules = NULL; interp->modules = NULL;
interp->modules_reloading = NULL;
interp->modules_by_index = NULL; interp->modules_by_index = NULL;
interp->sysdict = NULL; interp->sysdict = NULL;
interp->builtins = NULL; interp->builtins = NULL;
...@@ -114,7 +113,6 @@ PyInterpreterState_Clear(PyInterpreterState *interp) ...@@ -114,7 +113,6 @@ PyInterpreterState_Clear(PyInterpreterState *interp)
Py_CLEAR(interp->codec_error_registry); Py_CLEAR(interp->codec_error_registry);
Py_CLEAR(interp->modules); Py_CLEAR(interp->modules);
Py_CLEAR(interp->modules_by_index); Py_CLEAR(interp->modules_by_index);
Py_CLEAR(interp->modules_reloading);
Py_CLEAR(interp->sysdict); Py_CLEAR(interp->sysdict);
Py_CLEAR(interp->builtins); Py_CLEAR(interp->builtins);
Py_CLEAR(interp->importlib); Py_CLEAR(interp->importlib);
......
...@@ -314,9 +314,6 @@ Py_InitializeEx(int install_sigs) ...@@ -314,9 +314,6 @@ Py_InitializeEx(int install_sigs)
interp->modules = PyDict_New(); interp->modules = PyDict_New();
if (interp->modules == NULL) if (interp->modules == NULL)
Py_FatalError("Py_Initialize: can't make modules dictionary"); 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 */ /* Init Unicode implementation; relies on the codec registry */
if (_PyUnicode_Init() < 0) if (_PyUnicode_Init() < 0)
...@@ -680,7 +677,6 @@ Py_NewInterpreter(void) ...@@ -680,7 +677,6 @@ Py_NewInterpreter(void)
/* XXX The following is lax in error checking */ /* XXX The following is lax in error checking */
interp->modules = PyDict_New(); interp->modules = PyDict_New();
interp->modules_reloading = PyDict_New();
bimod = _PyImport_FindBuiltin("builtins"); bimod = _PyImport_FindBuiltin("builtins");
if (bimod != NULL) { if (bimod != NULL) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment