mirror of
https://github.com/python/cpython.git
synced 2025-08-31 22:18:28 +00:00
Issues #13959, 14647: Re-implement imp.reload() in Lib/imp.py.
Thanks to Eric Snow for the patch.
This commit is contained in:
parent
1fc3ec91cc
commit
62228dbd6c
6 changed files with 45 additions and 106 deletions
|
@ -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;
|
||||||
|
|
33
Lib/imp.py
33
Lib/imp.py
|
@ -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):
|
||||||
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)
|
||||||
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);
|
||||||
|
|
109
Python/import.c
109
Python/import.c
|
@ -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)
|
||||||
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
|
||||||
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)
|
||||||
|
|
||||||
#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[] = {
|
||||||
{"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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
/* 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) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue