mirror of
https://github.com/python/cpython.git
synced 2025-08-30 05:35:08 +00:00
gh-101758: Clean Up Uses of Import State (gh-101919)
This change is almost entirely moving code around and hiding import state behind internal API. We introduce no changes to behavior, nor to non-internal API. (Since there was already going to be a lot of churn, I took this as an opportunity to re-organize import.c into topically-grouped sections of code.) The motivation is to simplify a number of upcoming changes. Specific changes: * move existing import-related code to import.c, wherever possible * add internal API for interacting with import state (both global and per-interpreter) * use only API outside of import.c (to limit churn there when changing the location, etc.) * consolidate the import-related state of PyInterpreterState into a single struct field (this changes layout slightly) * add macros for import state in import.c (to simplify changing the location) * group code in import.c into sections *remove _PyState_AddModule() https://github.com/python/cpython/issues/101758
This commit is contained in:
parent
c1ce0d178f
commit
b2fc549278
20 changed files with 1496 additions and 1092 deletions
|
@ -156,79 +156,6 @@ Py_IsInitialized(void)
|
|||
}
|
||||
|
||||
|
||||
/* Global initializations. Can be undone by Py_FinalizeEx(). Don't
|
||||
call this twice without an intervening Py_FinalizeEx() call. When
|
||||
initializations fail, a fatal error is issued and the function does
|
||||
not return. On return, the first thread and interpreter state have
|
||||
been created.
|
||||
|
||||
Locking: you must hold the interpreter lock while calling this.
|
||||
(If the lock has not yet been initialized, that's equivalent to
|
||||
having the lock, but you cannot use multiple threads.)
|
||||
|
||||
*/
|
||||
static int
|
||||
init_importlib(PyThreadState *tstate, PyObject *sysmod)
|
||||
{
|
||||
assert(!_PyErr_Occurred(tstate));
|
||||
|
||||
PyInterpreterState *interp = tstate->interp;
|
||||
int verbose = _PyInterpreterState_GetConfig(interp)->verbose;
|
||||
|
||||
// Import _importlib through its frozen version, _frozen_importlib.
|
||||
if (verbose) {
|
||||
PySys_FormatStderr("import _frozen_importlib # frozen\n");
|
||||
}
|
||||
if (PyImport_ImportFrozenModule("_frozen_importlib") <= 0) {
|
||||
return -1;
|
||||
}
|
||||
PyObject *importlib = PyImport_AddModule("_frozen_importlib"); // borrowed
|
||||
if (importlib == NULL) {
|
||||
return -1;
|
||||
}
|
||||
interp->importlib = Py_NewRef(importlib);
|
||||
|
||||
// Import the _imp module
|
||||
if (verbose) {
|
||||
PySys_FormatStderr("import _imp # builtin\n");
|
||||
}
|
||||
PyObject *imp_mod = _PyImport_BootstrapImp(tstate);
|
||||
if (imp_mod == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (_PyImport_SetModuleString("_imp", imp_mod) < 0) {
|
||||
Py_DECREF(imp_mod);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Install importlib as the implementation of import
|
||||
PyObject *value = PyObject_CallMethod(importlib, "_install",
|
||||
"OO", sysmod, imp_mod);
|
||||
Py_DECREF(imp_mod);
|
||||
if (value == NULL) {
|
||||
return -1;
|
||||
}
|
||||
Py_DECREF(value);
|
||||
|
||||
assert(!_PyErr_Occurred(tstate));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static PyStatus
|
||||
init_importlib_external(PyThreadState *tstate)
|
||||
{
|
||||
PyObject *value;
|
||||
value = PyObject_CallMethod(tstate->interp->importlib,
|
||||
"_install_external_importers", "");
|
||||
if (value == NULL) {
|
||||
_PyErr_Print(tstate);
|
||||
return _PyStatus_ERR("external importer setup failed");
|
||||
}
|
||||
Py_DECREF(value);
|
||||
return _PyImportZip_Init(tstate);
|
||||
}
|
||||
|
||||
/* Helper functions to better handle the legacy C locale
|
||||
*
|
||||
* The legacy C locale assumes ASCII as the default text encoding, which
|
||||
|
@ -814,7 +741,8 @@ pycore_init_builtins(PyThreadState *tstate)
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (_PyImport_FixupBuiltin(bimod, "builtins", interp->modules) < 0) {
|
||||
PyObject *modules = _PyImport_GetModules(interp);
|
||||
if (_PyImport_FixupBuiltin(bimod, "builtins", modules) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -850,13 +778,9 @@ pycore_init_builtins(PyThreadState *tstate)
|
|||
}
|
||||
Py_DECREF(bimod);
|
||||
|
||||
// Get the __import__ function
|
||||
PyObject *import_func = _PyDict_GetItemStringWithError(interp->builtins,
|
||||
"__import__");
|
||||
if (import_func == NULL) {
|
||||
if (_PyImport_InitDefaultImportFunc(interp) < 0) {
|
||||
goto error;
|
||||
}
|
||||
interp->import_func = Py_NewRef(import_func);
|
||||
|
||||
assert(!_PyErr_Occurred(tstate));
|
||||
return _PyStatus_OK();
|
||||
|
@ -918,11 +842,10 @@ pycore_interp_init(PyThreadState *tstate)
|
|||
}
|
||||
|
||||
const PyConfig *config = _PyInterpreterState_GetConfig(interp);
|
||||
if (config->_install_importlib) {
|
||||
/* This call sets up builtin and frozen import support */
|
||||
if (init_importlib(tstate, sysmod) < 0) {
|
||||
return _PyStatus_ERR("failed to initialize importlib");
|
||||
}
|
||||
|
||||
status = _PyImport_InitCore(tstate, sysmod, config->_install_importlib);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
|
@ -1172,7 +1095,7 @@ init_interp_main(PyThreadState *tstate)
|
|||
return _PyStatus_ERR("failed to update the Python config");
|
||||
}
|
||||
|
||||
status = init_importlib_external(tstate);
|
||||
status = _PyImport_InitExternal(tstate);
|
||||
if (_PyStatus_EXCEPTION(status)) {
|
||||
return status;
|
||||
}
|
||||
|
@ -1379,8 +1302,11 @@ finalize_modules_delete_special(PyThreadState *tstate, int verbose)
|
|||
static const char * const sys_deletes[] = {
|
||||
"path", "argv", "ps1", "ps2",
|
||||
"last_type", "last_value", "last_traceback",
|
||||
"path_hooks", "path_importer_cache", "meta_path",
|
||||
"__interactivehook__",
|
||||
// path_hooks and path_importer_cache are cleared
|
||||
// by _PyImport_FiniExternal().
|
||||
// XXX Clear meta_path in _PyImport_FiniCore().
|
||||
"meta_path",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -1401,10 +1327,7 @@ finalize_modules_delete_special(PyThreadState *tstate, int verbose)
|
|||
|
||||
const char * const *p;
|
||||
for (p = sys_deletes; *p != NULL; p++) {
|
||||
if (verbose) {
|
||||
PySys_WriteStderr("# clear sys.%s\n", *p);
|
||||
}
|
||||
if (PyDict_SetItemString(interp->sysdict, *p, Py_None) < 0) {
|
||||
if (_PySys_ClearAttrString(interp, *p, verbose) < 0) {
|
||||
PyErr_WriteUnraisable(NULL);
|
||||
}
|
||||
}
|
||||
|
@ -1576,11 +1499,12 @@ finalize_clear_sys_builtins_dict(PyInterpreterState *interp, int verbose)
|
|||
|
||||
|
||||
/* Clear modules, as good as we can */
|
||||
// XXX Move most of this to import.c.
|
||||
static void
|
||||
finalize_modules(PyThreadState *tstate)
|
||||
{
|
||||
PyInterpreterState *interp = tstate->interp;
|
||||
PyObject *modules = interp->modules;
|
||||
PyObject *modules = _PyImport_GetModules(interp);
|
||||
if (modules == NULL) {
|
||||
// Already done
|
||||
return;
|
||||
|
@ -1645,12 +1569,12 @@ finalize_modules(PyThreadState *tstate)
|
|||
// clear PyInterpreterState.modules_by_index and
|
||||
// clear PyModuleDef.m_base.m_copy (of extensions not using the multi-phase
|
||||
// initialization API)
|
||||
_PyInterpreterState_ClearModules(interp);
|
||||
_PyImport_ClearModulesByIndex(interp);
|
||||
|
||||
// Clear and delete the modules directory. Actual modules will
|
||||
// still be there only if imported during the execution of some
|
||||
// destructor.
|
||||
Py_SETREF(interp->modules, NULL);
|
||||
_PyImport_ClearModules(interp);
|
||||
|
||||
// Collect garbage once more
|
||||
_PyGC_CollectNoFail(tstate);
|
||||
|
@ -1861,6 +1785,8 @@ Py_FinalizeEx(void)
|
|||
runtime->initialized = 0;
|
||||
runtime->core_initialized = 0;
|
||||
|
||||
// XXX Call something like _PyImport_Disable() here?
|
||||
|
||||
/* Destroy the state of all threads of the interpreter, except of the
|
||||
current thread. In practice, only daemon threads should still be alive,
|
||||
except if wait_for_thread_shutdown() has been cancelled by CTRL+C.
|
||||
|
@ -1910,6 +1836,7 @@ Py_FinalizeEx(void)
|
|||
PyGC_Collect();
|
||||
|
||||
/* Destroy all modules */
|
||||
_PyImport_FiniExternal(tstate->interp);
|
||||
finalize_modules(tstate);
|
||||
|
||||
/* Print debug stats if any */
|
||||
|
@ -1943,7 +1870,9 @@ Py_FinalizeEx(void)
|
|||
so it is possible to use tracemalloc in objects destructor. */
|
||||
_PyTraceMalloc_Fini();
|
||||
|
||||
/* Destroy the database used by _PyImport_{Fixup,Find}Extension */
|
||||
/* Finalize any remaining import state */
|
||||
// XXX Move these up to where finalize_modules() is currently.
|
||||
_PyImport_FiniCore(tstate->interp);
|
||||
_PyImport_Fini();
|
||||
|
||||
/* unload faulthandler module */
|
||||
|
@ -2183,7 +2112,11 @@ Py_EndInterpreter(PyThreadState *tstate)
|
|||
Py_FatalError("not the last thread");
|
||||
}
|
||||
|
||||
// XXX Call something like _PyImport_Disable() here?
|
||||
|
||||
_PyImport_FiniExternal(tstate->interp);
|
||||
finalize_modules(tstate);
|
||||
_PyImport_FiniCore(tstate->interp);
|
||||
|
||||
finalize_interp_clear(tstate);
|
||||
finalize_interp_delete(tstate->interp);
|
||||
|
@ -2232,8 +2165,8 @@ add_main_module(PyInterpreterState *interp)
|
|||
if (PyErr_Occurred()) {
|
||||
return _PyStatus_ERR("Failed to test __main__.__loader__");
|
||||
}
|
||||
PyObject *loader = PyObject_GetAttrString(interp->importlib,
|
||||
"BuiltinImporter");
|
||||
PyObject *loader = _PyImport_GetImportlibLoader(interp,
|
||||
"BuiltinImporter");
|
||||
if (loader == NULL) {
|
||||
return _PyStatus_ERR("Failed to retrieve BuiltinImporter");
|
||||
}
|
||||
|
@ -2739,7 +2672,7 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp)
|
|||
if (interp == NULL) {
|
||||
return;
|
||||
}
|
||||
PyObject *modules = interp->modules;
|
||||
PyObject *modules = _PyImport_GetModules(interp);
|
||||
if (modules == NULL || !PyDict_Check(modules)) {
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue