mirror of https://github.com/python/cpython
gh-105922: Add PyImport_AddModuleRef() function (#105923)
* Add tests on PyImport_AddModuleRef(), PyImport_AddModule() and PyImport_AddModuleObject(). * pythonrun.c: Replace Py_XNewRef(PyImport_AddModule(name)) with PyImport_AddModuleRef(name).
This commit is contained in:
parent
7f97c8e367
commit
03f1a132ee
|
@ -98,27 +98,40 @@ Importing Modules
|
||||||
an exception set on failure (the module still exists in this case).
|
an exception set on failure (the module still exists in this case).
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: PyObject* PyImport_AddModuleRef(const char *name)
|
||||||
|
|
||||||
|
Return the module object corresponding to a module name.
|
||||||
|
|
||||||
|
The *name* argument may be of the form ``package.module``. First check the
|
||||||
|
modules dictionary if there's one there, and if not, create a new one and
|
||||||
|
insert it in the modules dictionary.
|
||||||
|
|
||||||
|
Return a :term:`strong reference` to the module on success. Return ``NULL``
|
||||||
|
with an exception set on failure.
|
||||||
|
|
||||||
|
The module name *name* is decoded from UTF-8.
|
||||||
|
|
||||||
|
This function does not load or import the module; if the module wasn't
|
||||||
|
already loaded, you will get an empty module object. Use
|
||||||
|
:c:func:`PyImport_ImportModule` or one of its variants to import a module.
|
||||||
|
Package structures implied by a dotted name for *name* are not created if
|
||||||
|
not already present.
|
||||||
|
|
||||||
|
.. versionadded:: 3.13
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: PyObject* PyImport_AddModuleObject(PyObject *name)
|
.. c:function:: PyObject* PyImport_AddModuleObject(PyObject *name)
|
||||||
|
|
||||||
Return the module object corresponding to a module name. The *name* argument
|
Similar to :c:func:`PyImport_AddModuleRef`, but return a :term:`borrowed
|
||||||
may be of the form ``package.module``. First check the modules dictionary if
|
reference` and *name* is a Python :class:`str` object.
|
||||||
there's one there, and if not, create a new one and insert it in the modules
|
|
||||||
dictionary. Return ``NULL`` with an exception set on failure.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
This function does not load or import the module; if the module wasn't already
|
|
||||||
loaded, you will get an empty module object. Use :c:func:`PyImport_ImportModule`
|
|
||||||
or one of its variants to import a module. Package structures implied by a
|
|
||||||
dotted name for *name* are not created if not already present.
|
|
||||||
|
|
||||||
.. versionadded:: 3.3
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: PyObject* PyImport_AddModule(const char *name)
|
.. c:function:: PyObject* PyImport_AddModule(const char *name)
|
||||||
|
|
||||||
Similar to :c:func:`PyImport_AddModuleObject`, but the name is a UTF-8
|
Similar to :c:func:`PyImport_AddModuleRef`, but return a :term:`borrowed
|
||||||
encoded string instead of a Unicode object.
|
reference`.
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: PyObject* PyImport_ExecCodeModule(const char *name, PyObject *co)
|
.. c:function:: PyObject* PyImport_ExecCodeModule(const char *name, PyObject *co)
|
||||||
|
|
|
@ -974,6 +974,9 @@ PyCoro_New:PyFrameObject*:frame:0:
|
||||||
PyCoro_New:PyObject*:name:0:
|
PyCoro_New:PyObject*:name:0:
|
||||||
PyCoro_New:PyObject*:qualname:0:
|
PyCoro_New:PyObject*:qualname:0:
|
||||||
|
|
||||||
|
PyImport_AddModuleRef:PyObject*::+1:
|
||||||
|
PyImport_AddModuleRef:const char*:name::
|
||||||
|
|
||||||
PyImport_AddModule:PyObject*::0:reference borrowed from sys.modules
|
PyImport_AddModule:PyObject*::0:reference borrowed from sys.modules
|
||||||
PyImport_AddModule:const char*:name::
|
PyImport_AddModule:const char*:name::
|
||||||
|
|
||||||
|
|
|
@ -298,6 +298,7 @@ type,PyGetSetDef,3.2,,full-abi
|
||||||
var,PyGetSetDescr_Type,3.2,,
|
var,PyGetSetDescr_Type,3.2,,
|
||||||
function,PyImport_AddModule,3.2,,
|
function,PyImport_AddModule,3.2,,
|
||||||
function,PyImport_AddModuleObject,3.7,,
|
function,PyImport_AddModuleObject,3.7,,
|
||||||
|
function,PyImport_AddModuleRef,3.13,,
|
||||||
function,PyImport_AppendInittab,3.2,,
|
function,PyImport_AppendInittab,3.2,,
|
||||||
function,PyImport_ExecCodeModule,3.2,,
|
function,PyImport_ExecCodeModule,3.2,,
|
||||||
function,PyImport_ExecCodeModuleEx,3.2,,
|
function,PyImport_ExecCodeModuleEx,3.2,,
|
||||||
|
|
|
@ -426,6 +426,11 @@ New Features
|
||||||
APIs accepting the format codes always use ``Py_ssize_t`` for ``#`` formats.
|
APIs accepting the format codes always use ``Py_ssize_t`` for ``#`` formats.
|
||||||
(Contributed by Inada Naoki in :gh:`104922`.)
|
(Contributed by Inada Naoki in :gh:`104922`.)
|
||||||
|
|
||||||
|
* Add :c:func:`PyImport_AddModuleRef`: similar to
|
||||||
|
:c:func:`PyImport_AddModule`, but return a :term:`strong reference` instead
|
||||||
|
of a :term:`borrowed reference`.
|
||||||
|
(Contributed by Victor Stinner in :gh:`105922`.)
|
||||||
|
|
||||||
|
|
||||||
Porting to Python 3.13
|
Porting to Python 3.13
|
||||||
----------------------
|
----------------------
|
||||||
|
|
|
@ -43,6 +43,11 @@ PyAPI_FUNC(PyObject *) PyImport_AddModuleObject(
|
||||||
PyAPI_FUNC(PyObject *) PyImport_AddModule(
|
PyAPI_FUNC(PyObject *) PyImport_AddModule(
|
||||||
const char *name /* UTF-8 encoded string */
|
const char *name /* UTF-8 encoded string */
|
||||||
);
|
);
|
||||||
|
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000
|
||||||
|
PyAPI_FUNC(PyObject *) PyImport_AddModuleRef(
|
||||||
|
const char *name /* UTF-8 encoded string */
|
||||||
|
);
|
||||||
|
#endif
|
||||||
PyAPI_FUNC(PyObject *) PyImport_ImportModule(
|
PyAPI_FUNC(PyObject *) PyImport_ImportModule(
|
||||||
const char *name /* UTF-8 encoded string */
|
const char *name /* UTF-8 encoded string */
|
||||||
);
|
);
|
||||||
|
|
|
@ -2621,6 +2621,30 @@ class SinglephaseInitTests(unittest.TestCase):
|
||||||
# * module's global state was initialized, not reset
|
# * module's global state was initialized, not reset
|
||||||
|
|
||||||
|
|
||||||
|
@cpython_only
|
||||||
|
class CAPITests(unittest.TestCase):
|
||||||
|
def test_pyimport_addmodule(self):
|
||||||
|
# gh-105922: Test PyImport_AddModuleRef(), PyImport_AddModule()
|
||||||
|
# and PyImport_AddModuleObject()
|
||||||
|
import _testcapi
|
||||||
|
for name in (
|
||||||
|
'sys', # frozen module
|
||||||
|
'test', # package
|
||||||
|
__name__, # package.module
|
||||||
|
):
|
||||||
|
_testcapi.check_pyimport_addmodule(name)
|
||||||
|
|
||||||
|
def test_pyimport_addmodule_create(self):
|
||||||
|
# gh-105922: Test PyImport_AddModuleRef(), create a new module
|
||||||
|
import _testcapi
|
||||||
|
name = 'dontexist'
|
||||||
|
self.assertNotIn(name, sys.modules)
|
||||||
|
self.addCleanup(unload, name)
|
||||||
|
|
||||||
|
mod = _testcapi.check_pyimport_addmodule(name)
|
||||||
|
self.assertIs(mod, sys.modules[name])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# Test needs to be a package, so we can do relative imports.
|
# Test needs to be a package, so we can do relative imports.
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -328,6 +328,7 @@ SYMBOL_NAMES = (
|
||||||
"PyGetSetDescr_Type",
|
"PyGetSetDescr_Type",
|
||||||
"PyImport_AddModule",
|
"PyImport_AddModule",
|
||||||
"PyImport_AddModuleObject",
|
"PyImport_AddModuleObject",
|
||||||
|
"PyImport_AddModuleRef",
|
||||||
"PyImport_AppendInittab",
|
"PyImport_AppendInittab",
|
||||||
"PyImport_ExecCodeModule",
|
"PyImport_ExecCodeModule",
|
||||||
"PyImport_ExecCodeModuleEx",
|
"PyImport_ExecCodeModuleEx",
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Add :c:func:`PyImport_AddModuleRef`: similar to :c:func:`PyImport_AddModule`,
|
||||||
|
but return a :term:`strong reference` instead of a :term:`borrowed reference`.
|
||||||
|
Patch by Victor Stinner.
|
|
@ -2428,3 +2428,5 @@
|
||||||
added = '3.12'
|
added = '3.12'
|
||||||
[const.Py_TPFLAGS_ITEMS_AT_END]
|
[const.Py_TPFLAGS_ITEMS_AT_END]
|
||||||
added = '3.12'
|
added = '3.12'
|
||||||
|
[function.PyImport_AddModuleRef]
|
||||||
|
added = '3.13'
|
||||||
|
|
|
@ -3325,6 +3325,53 @@ test_atexit(PyObject *self, PyObject *Py_UNUSED(args))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
check_pyimport_addmodule(PyObject *self, PyObject *args)
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &name)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// test PyImport_AddModuleRef()
|
||||||
|
PyObject *module = PyImport_AddModuleRef(name);
|
||||||
|
if (module == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
assert(PyModule_Check(module));
|
||||||
|
// module is a strong reference
|
||||||
|
|
||||||
|
// test PyImport_AddModule()
|
||||||
|
PyObject *module2 = PyImport_AddModule(name);
|
||||||
|
if (module2 == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
assert(PyModule_Check(module2));
|
||||||
|
assert(module2 == module);
|
||||||
|
// module2 is a borrowed ref
|
||||||
|
|
||||||
|
// test PyImport_AddModuleObject()
|
||||||
|
PyObject *name_obj = PyUnicode_FromString(name);
|
||||||
|
if (name_obj == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
PyObject *module3 = PyImport_AddModuleObject(name_obj);
|
||||||
|
Py_DECREF(name_obj);
|
||||||
|
if (module3 == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
assert(PyModule_Check(module3));
|
||||||
|
assert(module3 == module);
|
||||||
|
// module3 is a borrowed ref
|
||||||
|
|
||||||
|
return module;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_DECREF(module);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyMethodDef TestMethods[] = {
|
static PyMethodDef TestMethods[] = {
|
||||||
{"set_errno", set_errno, METH_VARARGS},
|
{"set_errno", set_errno, METH_VARARGS},
|
||||||
{"test_config", test_config, METH_NOARGS},
|
{"test_config", test_config, METH_NOARGS},
|
||||||
|
@ -3468,6 +3515,7 @@ static PyMethodDef TestMethods[] = {
|
||||||
{"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL},
|
{"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL},
|
||||||
{"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL},
|
{"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL},
|
||||||
{"test_atexit", test_atexit, METH_NOARGS},
|
{"test_atexit", test_atexit, METH_NOARGS},
|
||||||
|
{"check_pyimport_addmodule", check_pyimport_addmodule, METH_VARARGS},
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -288,6 +288,7 @@ EXPORT_FUNC(PyGILState_GetThisThreadState)
|
||||||
EXPORT_FUNC(PyGILState_Release)
|
EXPORT_FUNC(PyGILState_Release)
|
||||||
EXPORT_FUNC(PyImport_AddModule)
|
EXPORT_FUNC(PyImport_AddModule)
|
||||||
EXPORT_FUNC(PyImport_AddModuleObject)
|
EXPORT_FUNC(PyImport_AddModuleObject)
|
||||||
|
EXPORT_FUNC(PyImport_AddModuleRef)
|
||||||
EXPORT_FUNC(PyImport_AppendInittab)
|
EXPORT_FUNC(PyImport_AppendInittab)
|
||||||
EXPORT_FUNC(PyImport_ExecCodeModule)
|
EXPORT_FUNC(PyImport_ExecCodeModule)
|
||||||
EXPORT_FUNC(PyImport_ExecCodeModuleEx)
|
EXPORT_FUNC(PyImport_ExecCodeModuleEx)
|
||||||
|
|
|
@ -350,20 +350,38 @@ import_add_module(PyThreadState *tstate, PyObject *name)
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyImport_AddModuleRef(const char *name)
|
||||||
|
{
|
||||||
|
PyObject *name_obj = PyUnicode_FromString(name);
|
||||||
|
if (name_obj == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
|
PyObject *module = import_add_module(tstate, name_obj);
|
||||||
|
Py_DECREF(name_obj);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
PyImport_AddModuleObject(PyObject *name)
|
PyImport_AddModuleObject(PyObject *name)
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
PyObject *mod = import_add_module(tstate, name);
|
PyObject *mod = import_add_module(tstate, name);
|
||||||
if (mod) {
|
if (!mod) {
|
||||||
PyObject *ref = PyWeakref_NewRef(mod, NULL);
|
return NULL;
|
||||||
Py_DECREF(mod);
|
|
||||||
if (ref == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
mod = PyWeakref_GetObject(ref);
|
|
||||||
Py_DECREF(ref);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gh-86160: PyImport_AddModuleObject() returns a borrowed reference
|
||||||
|
PyObject *ref = PyWeakref_NewRef(mod, NULL);
|
||||||
|
Py_DECREF(mod);
|
||||||
|
if (ref == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mod = PyWeakref_GetObject(ref);
|
||||||
|
Py_DECREF(ref);
|
||||||
return mod; /* borrowed reference */
|
return mod; /* borrowed reference */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2240,11 +2258,12 @@ init_importlib(PyThreadState *tstate, PyObject *sysmod)
|
||||||
if (PyImport_ImportFrozenModule("_frozen_importlib") <= 0) {
|
if (PyImport_ImportFrozenModule("_frozen_importlib") <= 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
PyObject *importlib = PyImport_AddModule("_frozen_importlib"); // borrowed
|
|
||||||
|
PyObject *importlib = PyImport_AddModuleRef("_frozen_importlib");
|
||||||
if (importlib == NULL) {
|
if (importlib == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
IMPORTLIB(interp) = Py_NewRef(importlib);
|
IMPORTLIB(interp) = importlib;
|
||||||
|
|
||||||
// Import the _imp module
|
// Import the _imp module
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
|
|
|
@ -406,7 +406,7 @@ _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit,
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
PyObject *main_module = Py_XNewRef(PyImport_AddModule("__main__"));
|
PyObject *main_module = PyImport_AddModuleRef("__main__");
|
||||||
if (main_module == NULL)
|
if (main_module == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
PyObject *dict = PyModule_GetDict(main_module); // borrowed ref
|
PyObject *dict = PyModule_GetDict(main_module); // borrowed ref
|
||||||
|
@ -502,7 +502,7 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit,
|
||||||
int
|
int
|
||||||
PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags)
|
PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags)
|
||||||
{
|
{
|
||||||
PyObject *main_module = Py_XNewRef(PyImport_AddModule("__main__"));
|
PyObject *main_module = PyImport_AddModuleRef("__main__");
|
||||||
if (main_module == NULL) {
|
if (main_module == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue