8000 bpo-28411: Support other mappings in PyInterpreterState.modules. by ericsnowcurrently · Pull Request #3593 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-28411: Support other mappings in PyInterpreterState.modules. #3593

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8f3ecfc
Add _PyImport_GetModule*.
ericsnowcurrently May 18, 2017
9dc9ded
Allow sys.modules to be any mapping.
ericsnowcurrently May 18, 2017
f2a54b1
Add _PyImport_SetModule*.
ericsnowcurrently May 18, 2017
502e138
Add PyImport_GetModule().
ericsnowcurrently May 18, 2017
ec8c504
Decref the module when done.
ericsnowcurrently May 25, 2017
a1546f6
Fix ref counts.
ericsnowcurrently May 18, 2017
5a5fad1
Look up "new" modules in the given modules dict.
ericsnowcurrently May 18, 2017
db0a247
Fix error checking.
ericsnowcurrently May 20, 2017
7082b47
Use PyImport_GetModuleDict() in PyImport_GetModule().
ericsnowcurrently May 23, 2017
5082c47
Add a missing incref.
ericsnowcurrently May 25, 2017
bb03872
Add a Misc/NEWS entry.
ericsnowcurrently Sep 4, 2017
2e07296
Make the docs for PyImport_GetModule() more clear.
ericsnowcurrently Sep 4, 2017
4631163
Fix style (bracket placement).
ericsnowcurrently Sep 4, 2017
5b154b3
Drop _PyImport_GetModuleString().
ericsnowcurrently Sep 4, 2017
33174f3
Use PyDict_CheckExact() for sys.modules in fast case.
ericsnowcurrently Sep 4, 2017
e50e258
Do not use PyMapping_HasKey() with an error set.
ericsnowcurrently Sep 4, 2017
23cf493
Revert a code order change.
ericsnowcurrently Sep 4, 2017
eed5e24
Switch the code order back.
ericsnowcurrently Sep 4, 2017
bcc72a5
Only use PyDict_* for dicts.
ericsnowcurrently Sep 12, 2017
981dbd2
Add a reference while cleaning up.
ericsnowcurrently Sep 12, 2017
0fe1aff
Fix _pickle.
ericsnowcurrently Sep 14, 2017
d4d9219
Fix the NEWS entry.
ericsnowcurrently Sep 14, 2017
9c39295
Return a borrowed reference from _PyImport_GetModuleWithError().
ericsnowcurrently Sep 15, 2017
446acd5
Fix some ref leaks.
ericsnowcurrently Sep 15, 2017
540b99a
Add a fast path for pickle.
ericsnowcurrently Sep 15, 2017
5f0735b
Ignore errors from PyObject_GetItem().
ericsnowcurrently Sep 15, 2017
63beead
Factor out _checkmodule.
ericsnowcurrently Sep 15, 2017
00f3f24
Drop an extra INCREF.
ericsnowcurrently Sep 15, 2017
5a7bba2
Drop _PyImport_GetModule() and _PyImport_GetModuleWithError().
ericsnowcurrently Sep 15, 2017
3a73b52
tabs to spaces
ericsnowcurrently Sep 15, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Doc/c-api/import.rst
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,13 @@ Importing Modules
Return the dictionary used for the module administration (a.k.a.
``sys.modules``). Note that this is a per-interpreter variable.

.. c:function:: PyObject* PyImport_GetModule(PyObject *name)

Return the already imported module with the given name. If the
module has not been imported yet then returns NULL but does not set
an error. Returns NULL and sets an error if the lookup failed.

.. versionadded:: 3.7

.. c:function:: PyObject* PyImport_GetImporter(PyObject *path)

Expand Down
6 changes: 6 additions & 0 deletions Include/import.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,14 @@ PyAPI_FUNC(PyObject *) PyImport_ExecCodeModuleObject(
);
#endif
PyAPI_FUNC(PyObject *) PyImport_GetModuleDict(void);
PyAPI_FUNC(PyObject *) PyImport_GetModule(PyObject *name);
#ifndef Py_LIMITED_API
PyAPI_FUNC(int) _PyImport_IsInitialized(PyInterpreterState *);
PyAPI_FUNC(PyObject *) _PyImport_GetModuleId(struct _Py_Identifier *name);
PyAPI_FUNC(PyObject *) _PyImport_AddModuleObject(PyObject *name,
PyObject *modules);
PyAPI_FUNC(int) _PyImport_SetModule(PyObject *name, PyObject *module);
PyAPI_FUNC(int) _PyImport_SetModuleString(const char *name, PyObject* module);
#endif
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03030000
PyAPI_FUNC(PyObject *) PyImport_AddModuleObject(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Switch to the abstract API when dealing with ``PyInterpreterState.modules``.
This allows later support for all dict subclasses and other Mapping
implementations. Also add a ``PyImport_GetModule()`` function to reduce
a bunch of duplicated code.
107 changes: 68 additions & 39 deletions Modules/_pickle.c
Original file line number Diff line number Diff line change
Expand Up @@ -1650,13 +1650,40 @@ getattribute(PyObject *obj, PyObject *name, int allow_qualname)
return attr;
}

static int
_checkmodule(PyObject *module_name, PyObject *module,
PyObject *global, PyObject *dotted_path)
{
if (module == Py_None) {
return -1;
}
if (PyUnicode_Check(module_name) &&
_PyUnicode_EqualToASCIIString(module_name, "__main__")) {
return -1;
}

PyObject *candidate = get_deep_attribute(module, dotted_path, NULL);
if (candidate == NULL) {
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Clear();
}
return -1;
}
if (candidate != global) {
Py_DECREF(candidate);
return -1;
}
Py_DECREF(candidate);
return 0;
}

static PyObject *
whichmodule(PyObject *global, PyObject *dotted_path)
{
PyObject *module_name;
PyObject *modules_dict;
PyObject *module;
PyObject *module = NULL;
Py_ssize_t i;
PyObject *modules;
_Py_IDENTIFIER(__module__);
_Py_IDENTIFIER(modules);
_Py_IDENTIFIER(__main__);
Expand All @@ -1679,35 +1706,48 @@ whichmodule(PyObject *global, PyObject *dotted_path)
assert(module_name == NULL);

/* Fallback on walking sys.modules */
modules_dict = _PySys_GetObjectId(&PyId_modules);
if (modules_dict == NULL) {
modules = _PySys_GetObjectId(&PyId_modules);
if (modules == NULL) {
PyErr_SetString(PyExc_RuntimeError, "unable to get sys.modules");
return NULL;
}

i = 0;
while (PyDict_Next(modules_dict, &i, &module_name, &module)) {
PyObject *candidate;
if (PyUnicode_Check(module_name) &&
_PyUnicode_EqualToASCIIString(module_name, "__main__"))
continue;
if (module == Py_None)
continue;

candidate = get_deep_attribute(module, dotted_path, NULL);
if (candidate == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
if (PyDict_CheckExact(modules)) {
i = 0;
while (PyDict_Next(modules, &i, &module_name, &module)) {
if (_checkmodule(module_name, module, global, dotted_path) == 0) {
Py_INCREF(module_name);
return module_name;
}
if (PyErr_Occurred()) {
return NULL;
PyErr_Clear();
continue;
}
}

if (candidate == global) {
Py_INCREF(module_name);
Py_DECREF(candidate);
return module_name;
}
else {
PyObject *iterator = PyObject_GetIter(modules);
if (iterator == NULL) {
return NULL;
}
Py_DECREF(candidate);
while ((module_name = PyIter_Next(iterator))) {
module = PyObject_GetItem(modules, module_name);
if (module == NULL) {
Py_DECREF(module_name);
Py_DECREF(iterator);
return NULL;
}
if (_checkmodule(module_name, module, global, dotted_path) == 0) {
Py_DECREF(module);
Py_DECREF(iterator);
return module_name;
}
Py_DECREF(module);
Py_DECREF(module_name);
if (PyErr_Occurred()) {
Py_DECREF(iterator);
return NULL;
}
}
Py_DECREF(iterator);
}

/* If no module is found, use __main__. */
Expand Down Expand Up @@ -6425,9 +6465,7 @@ _pickle_Unpickler_find_class_impl(UnpicklerObject *self,
/*[clinic end generated code: output=becc08d7f9ed41e3 input=e2e6a865de093ef4]*/
{
PyObject *global;
PyObject *modules_dict;
PyObject *module;
_Py_IDENTIFIER(modules);

/* Try to map the old names used in Python 2.x to the new ones used in
Python 3.x. We do this only with old pickle protocols and when the
Expand Down Expand Up @@ -6484,25 +6522,16 @@ _pickle_Unpickler_find_class_impl(UnpicklerObject *self,
}
}

modules_dict = _PySys_GetObjectId(&PyId_modules);
if (modules_dict == NULL) {
PyErr_SetString(PyExc_RuntimeError, "unable to get sys.modules");
return NULL;
}

module = PyDict_GetItemWithError(modules_dict, module_name);
module = PyImport_GetModule(module_name);
if (module == NULL) {
if (PyErr_Occurred())
return NULL;
module = PyImport_Import(module_name);
if (module == NULL)
9E88 return NULL;
global = getattribute(module, global_name, self->proto >= 4);
Py_DECREF(module);
}
else {
global = getattribute(module, global_name, self->proto >= 4);
}
global = getattribute(module, global_name, self->proto >= 4);
Py_DECREF(module);
return global;
}

Expand Down
10 changes: 2 additions & 8 deletions Modules/pyexpat.c
Original file line number Diff line number Diff line change
Expand Up @@ -1643,7 +1643,6 @@ MODULE_INITFUNC(void)
PyObject *errors_module;
PyObject *modelmod_name;
PyObject *model_module;
PyObject *sys_modules;
PyObject *tmpnum, *tmpstr;
PyObject *codes_dict;
PyObject *rev_codes_dict;
Expand Down Expand Up @@ -1693,11 +1692,6 @@ MODULE_INITFUNC(void)
*/
PyModule_AddStringConstant(m, "native_encoding", "UTF-8");

sys_modules = PySys_GetObject("modules");
if (sys_modules == NULL) {
Py_DECREF(m);
return NULL;
}
d = PyModule_GetDict(m);
if (d == NULL) {
Py_DECREF(m);
Expand All @@ -1707,7 +1701,7 @@ MODULE_INITF F438 UNC(void)
if (errors_module == NULL) {
errors_module = PyModule_New(MODULE_NAME ".errors");
if (errors_module != NULL) {
PyDict_SetItem(sys_modules, errmod_name, errors_module);
_PyImport_SetModule(errmod_name, errors_module);
/* gives away the reference to errors_module */
PyModule_AddObject(m, "errors", errors_module);
}
Expand All @@ -1717,7 +1711,7 @@ MODULE_INITFUNC(void)
if (model_module == NULL) {
model_module = PyModule_New(MODULE_NAME ".model");
if (model_module != NULL) {
PyDict_SetItem(sys_modules, modelmod_name, model_module);
_PyImport_SetModule(modelmod_name, model_module);
/* gives away the reference to model_module */
PyModule_AddObject(m, "model", model_module);
}
Expand Down
4 changes: 1 addition & 3 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -3913,10 +3913,8 @@ import_copyreg(void)
by storing a reference to the cached module in a static variable, but
this broke when multiple embedded interpreters were in use (see issue
#17408 and #19088). */
PyObject *modules = PyImport_GetModuleDict();
copyreg_module = PyDict_GetItemWithError(modules, copyreg_str);
copyreg_module = PyImport_GetModule(copyreg_str);
if (copyreg_module != NULL) {
Py_INCREF(copyreg_module);
return copyreg_module;
}
if (PyErr_Occurred()) {
Expand Down
7 changes: 1 addition & 6 deletions Python/_warnings.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ static PyObject *
get_warnings_attr(const char *attr, int try_import)
{
static PyObject *warnings_str = NULL;
PyObject *all_modules;
PyObject *warnings_module, *obj;

if (warnings_str == NULL) {
Expand All @@ -58,13 +57,9 @@ get_warnings_attr(const char *attr, int try_import)
}
}
else {
all_modules = PyImport_GetModuleDict();

warnings_module = PyDict_GetItem(all_modules, warnings_str);
warnings_module = PyImport_GetModule(warnings_str);
if (warnings_module == NULL)
return NULL;

Py_INCREF(warnings_module);
}

if (!PyObject_HasAttrString(warnings_module, attr)) {
Expand Down
3 changes: 1 addition & 2 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -4935,13 +4935,12 @@ import_from(PyObject *v, PyObject *name)
Py_DECREF(pkgname);
return NULL;
}
x = PyDict_GetItem(PyImport_GetModuleDict(), fullmodname);
x = PyImport_GetModule(fullmodname);
Py_DECREF(fullmodname);
if (x == NULL) {
goto error;
}
Py_DECREF(pkgname);
Py_INCREF(x);
return x;
error:
pkgpath = PyModule_GetFilenameObject(v);
Expand Down
Loading
0