Skip to content

Commit 2f3cc67

Browse files
committed
gh-106915: Add PyImport_ImportOrAddModule() function
Remove PyImport_AddModuleRef() function.
1 parent 13405ec commit 2f3cc67

File tree

13 files changed

+95
-54
lines changed

13 files changed

+95
-54
lines changed

Doc/c-api/import.rst

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -98,16 +98,22 @@ Importing Modules
9898
an exception set on failure (the module still exists in this case).
9999
100100
101-
.. c:function:: PyObject* PyImport_AddModuleRef(const char *name)
101+
.. c:function:: int PyImport_ImportOrAddModule(const char *name, PyObject **module)
102102
103-
Return the module object corresponding to a module name.
103+
Create a new module and store it in :data:`sys.modules`, or get an already
104+
imported module from :data:`sys.modules`.
104105
105-
The *name* argument may be of the form ``package.module``. First check the
106-
modules dictionary if there's one there, and if not, create a new one and
107-
insert it in the modules dictionary.
106+
First check the modules dictionary if there's one there, and if not, create
107+
a new one and insert it in the modules dictionary.
108108
109-
Return a :term:`strong reference` to the module on success. Return ``NULL``
110-
with an exception set on failure.
109+
The *name* argument may be of the form ``package.module``.
110+
111+
- If the module does not exist, create a module, store it in
112+
:data:`sys.modules`, set *\*module* to a :term:`strong reference` to the
113+
module, and return 1.
114+
- If the module was already imported, set *\*module* to a :term:`strong
115+
reference` to the existing module, and return 0.
116+
- On error, raise an exception, set *\*module* to NULL, and return -1.
111117
112118
The module name *name* is decoded from UTF-8.
113119
@@ -122,16 +128,18 @@ Importing Modules
122128
123129
.. c:function:: PyObject* PyImport_AddModuleObject(PyObject *name)
124130
125-
Similar to :c:func:`PyImport_AddModuleRef`, but return a :term:`borrowed
126-
reference` and *name* is a Python :class:`str` object.
131+
Similar to :c:func:`PyImport_ImportOrAddModule`, but return a :term:`borrowed
132+
reference`, *name* is a Python :class:`str` object, and don't provide the
133+
information if the module was created or was already imported.
127134
128135
.. versionadded:: 3.3
129136
130137
131138
.. c:function:: PyObject* PyImport_AddModule(const char *name)
132139
133-
Similar to :c:func:`PyImport_AddModuleRef`, but return a :term:`borrowed
134-
reference`.
140+
Similar to :c:func:`PyImport_ImportOrAddModule`, but return a :term:`borrowed
141+
reference`, and don't provide the information if the module was created or
142+
was already imported.
135143
136144
137145
.. c:function:: PyObject* PyImport_ExecCodeModule(const char *name, PyObject *co)

Doc/data/refcounts.dat

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -974,9 +974,6 @@ PyCoro_New:PyFrameObject*:frame:0:
974974
PyCoro_New:PyObject*:name:0:
975975
PyCoro_New:PyObject*:qualname:0:
976976

977-
PyImport_AddModuleRef:PyObject*::+1:
978-
PyImport_AddModuleRef:const char*:name::
979-
980977
PyImport_AddModule:PyObject*::0:reference borrowed from sys.modules
981978
PyImport_AddModule:const char*:name::
982979

Doc/data/stable_abi.dat

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Doc/whatsnew/3.13.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,9 +1018,10 @@ New Features
10181018
APIs accepting the format codes always use ``Py_ssize_t`` for ``#`` formats.
10191019
(Contributed by Inada Naoki in :gh:`104922`.)
10201020

1021-
* Add :c:func:`PyImport_AddModuleRef`: similar to
1022-
:c:func:`PyImport_AddModule`, but return a :term:`strong reference` instead
1023-
of a :term:`borrowed reference`.
1021+
* Add :c:func:`PyImport_ImportOrAddModule`: similar to
1022+
:c:func:`PyImport_AddModule`, but get a :term:`strong reference` instead
1023+
of a :term:`borrowed reference` and return 0 if the module was already
1024+
imported.
10241025
(Contributed by Victor Stinner in :gh:`105922`.)
10251026

10261027
* Add :c:func:`PyWeakref_GetRef` function: similar to

Include/import.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,22 @@ PyAPI_FUNC(PyObject *) PyImport_AddModuleObject(
4343
PyAPI_FUNC(PyObject *) PyImport_AddModule(
4444
const char *name /* UTF-8 encoded string */
4545
);
46+
4647
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000
47-
PyAPI_FUNC(PyObject *) PyImport_AddModuleRef(
48-
const char *name /* UTF-8 encoded string */
48+
// Create a new module and store it in sys.modules, or get an already imported
49+
// module from sys.modules.
50+
//
51+
// - If the module does not exist, create a module, store it in sys.modules,
52+
// set '*module' to a strong reference to the module, and return 1.
53+
// - If the module was already imported, set '*module' to a strong reference
54+
// to the existing module, and return 0.
55+
// - On error, raise an exception, set '*module' to NULL, and return -1.
56+
PyAPI_FUNC(int) PyImport_ImportOrAddModule(
57+
const char *name, // UTF-8 encoded string
58+
PyObject **module
4959
);
5060
#endif
61+
5162
PyAPI_FUNC(PyObject *) PyImport_ImportModule(
5263
const char *name /* UTF-8 encoded string */
5364
);

Lib/test/test_import/__init__.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2669,24 +2669,25 @@ def test_basic_multiple_interpreters_reset_each(self):
26692669
@cpython_only
26702670
class CAPITests(unittest.TestCase):
26712671
def test_pyimport_addmodule(self):
2672-
# gh-105922: Test PyImport_AddModuleRef(), PyImport_AddModule()
2673-
# and PyImport_AddModuleObject()
2672+
# gh-105922: Test PyImport_ImportOrAddModule(), PyImport_AddModule()
2673+
# and PyImport_AddModuleObject(): module already exists.
26742674
import _testcapi
26752675
for name in (
26762676
'sys', # frozen module
26772677
'test', # package
26782678
__name__, # package.module
26792679
):
2680-
_testcapi.check_pyimport_addmodule(name)
2680+
self.assertIn(name, sys.modules)
2681+
_testcapi.check_pyimport_addmodule(name, False)
26812682

26822683
def test_pyimport_addmodule_create(self):
2683-
# gh-105922: Test PyImport_AddModuleRef(), create a new module
2684+
# gh-105922: Test PyImport_ImportOrAddModule(): create a new module
26842685
import _testcapi
26852686
name = 'dontexist'
26862687
self.assertNotIn(name, sys.modules)
26872688
self.addCleanup(unload, name)
26882689

2689-
mod = _testcapi.check_pyimport_addmodule(name)
2690+
mod = _testcapi.check_pyimport_addmodule(name, True)
26902691
self.assertIs(mod, sys.modules[name])
26912692

26922693

Lib/test/test_stable_abi_ctypes.py

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add :c:func:`PyImport_ImportOrAddModule` function and remove
2+
:c:func:`PyImport_AddModuleRef` function. Patch by Victor Stinner.

Misc/stable_abi.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2428,7 +2428,7 @@
24282428
added = '3.12'
24292429
[const.Py_TPFLAGS_ITEMS_AT_END]
24302430
added = '3.12'
2431-
[function.PyImport_AddModuleRef]
2431+
[function.PyImport_ImportOrAddModule]
24322432
added = '3.13'
24332433
[function.PyWeakref_GetRef]
24342434
added = '3.13'

Modules/_testcapimodule.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3036,15 +3036,19 @@ static PyObject *
30363036
check_pyimport_addmodule(PyObject *self, PyObject *args)
30373037
{
30383038
const char *name;
3039-
if (!PyArg_ParseTuple(args, "s", &name)) {
3039+
int is_new;
3040+
if (!PyArg_ParseTuple(args, "si", &name, &is_new)) {
30403041
return NULL;
30413042
}
3043+
// name must be the name of a module which is already in sys.modules
30423044

3043-
// test PyImport_AddModuleRef()
3044-
PyObject *module = PyImport_AddModuleRef(name);
3045-
if (module == NULL) {
3045+
// test PyImport_ImportOrAddModule()
3046+
PyObject *module = UNINITIALIZED_PTR;
3047+
int res = PyImport_ImportOrAddModule(name, &module);
3048+
if (res < 0) {
30463049
return NULL;
30473050
}
3051+
assert(res == is_new);
30483052
assert(PyModule_Check(module));
30493053
// module is a strong reference
30503054

PC/python3dll.c

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/import.c

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ PyImport_GetModule(PyObject *name)
291291
if not, create a new one and insert it in the modules dictionary. */
292292

293293
static PyObject *
294-
import_add_module(PyThreadState *tstate, PyObject *name)
294+
import_add_module(PyThreadState *tstate, PyObject *name, int *is_new)
295295
{
296296
PyObject *modules = MODULES(tstate->interp);
297297
if (modules == NULL) {
@@ -305,39 +305,55 @@ import_add_module(PyThreadState *tstate, PyObject *name)
305305
return NULL;
306306
}
307307
if (m != NULL && PyModule_Check(m)) {
308+
if (is_new) {
309+
*is_new = 0;
310+
}
308311
return m;
309312
}
310313
Py_XDECREF(m);
314+
311315
m = PyModule_NewObject(name);
312-
if (m == NULL)
316+
if (m == NULL) {
313317
return NULL;
318+
}
314319
if (PyObject_SetItem(modules, name, m) != 0) {
315320
Py_DECREF(m);
316321
return NULL;
317322
}
318323

324+
if (is_new) {
325+
*is_new = 1;
326+
}
319327
return m;
320328
}
321329

322-
PyObject *
323-
PyImport_AddModuleRef(const char *name)
330+
int
331+
PyImport_ImportOrAddModule(const char *name, PyObject **pmodule)
324332
{
325333
PyObject *name_obj = PyUnicode_FromString(name);
326334
if (name_obj == NULL) {
327-
return NULL;
335+
*pmodule = NULL;
336+
return -1;
328337
}
329338
PyThreadState *tstate = _PyThreadState_GET();
330-
PyObject *module = import_add_module(tstate, name_obj);
339+
int is_new;
340+
PyObject *module = import_add_module(tstate, name_obj, &is_new);
331341
Py_DECREF(name_obj);
332-
return module;
342+
343+
*pmodule = module;
344+
if (module == NULL) {
345+
assert(PyErr_Occurred());
346+
return -1;
347+
}
348+
return is_new;
333349
}
334350

335351

336352
PyObject *
337353
PyImport_AddModuleObject(PyObject *name)
338354
{
339355
PyThreadState *tstate = _PyThreadState_GET();
340-
PyObject *mod = import_add_module(tstate, name);
356+
PyObject *mod = import_add_module(tstate, name, NULL);
341357
if (!mod) {
342358
return NULL;
343359
}
@@ -351,7 +367,7 @@ PyImport_AddModuleObject(PyObject *name)
351367
// unknown. With weakref we can be sure that we get either a reference to
352368
// live object or NULL.
353369
//
354-
// Use PyImport_AddModuleRef() to avoid these issues.
370+
// Use PyImport_ImportOrAddModule() to avoid these issues.
355371
PyObject *ref = PyWeakref_NewRef(mod, NULL);
356372
Py_DECREF(mod);
357373
if (ref == NULL) {
@@ -1258,7 +1274,7 @@ import_find_extension(PyThreadState *tstate, PyObject *name,
12581274
return NULL;
12591275
}
12601276
}
1261-
mod = import_add_module(tstate, name);
1277+
mod = import_add_module(tstate, name, NULL);
12621278
if (mod == NULL) {
12631279
return NULL;
12641280
}
@@ -1386,7 +1402,7 @@ create_builtin(PyThreadState *tstate, PyObject *name, PyObject *spec)
13861402
if (_PyUnicode_EqualToASCIIString(name, p->name)) {
13871403
if (p->initfunc == NULL) {
13881404
/* Cannot re-init internal module ("sys" or "builtins") */
1389-
return import_add_module(tstate, name);
1405+
return import_add_module(tstate, name, NULL);
13901406
}
13911407
mod = (*p->initfunc)();
13921408
if (mod == NULL) {
@@ -1671,7 +1687,7 @@ module_dict_for_exec(PyThreadState *tstate, PyObject *name)
16711687
{
16721688
PyObject *m, *d;
16731689

1674-
m = import_add_module(tstate, name);
1690+
m = import_add_module(tstate, name, NULL);
16751691
if (m == NULL)
16761692
return NULL;
16771693
/* If the module is being reloaded, we get the old module back
@@ -2110,7 +2126,7 @@ PyImport_ImportFrozenModuleObject(PyObject *name)
21102126
if (info.is_package) {
21112127
/* Set __path__ to the empty list */
21122128
PyObject *l;
2113-
m = import_add_module(tstate, name);
2129+
m = import_add_module(tstate, name, NULL);
21142130
if (m == NULL)
21152131
goto err_return;
21162132
d = PyModule_GetDict(m);
@@ -2252,8 +2268,8 @@ init_importlib(PyThreadState *tstate, PyObject *sysmod)
22522268
return -1;
22532269
}
22542270

2255-
PyObject *importlib = PyImport_AddModuleRef("_frozen_importlib");
2256-
if (importlib == NULL) {
2271+
PyObject *importlib;
2272+
if (PyImport_ImportOrAddModule("_frozen_importlib", &importlib) < 0) {
22572273
return -1;
22582274
}
22592275
IMPORTLIB(interp) = importlib;
@@ -3464,7 +3480,7 @@ _imp_init_frozen_impl(PyObject *module, PyObject *name)
34643480
if (ret == 0) {
34653481
Py_RETURN_NONE;
34663482
}
3467-
return import_add_module(tstate, name);
3483+
return import_add_module(tstate, name, NULL);
34683484
}
34693485

34703486
/*[clinic input]

Python/pythonrun.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,8 @@ PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename,
277277
return parse_res;
278278
}
279279

280-
PyObject *main_module = PyImport_AddModuleRef("__main__");
281-
if (main_module == NULL) {
280+
PyObject *main_module;
281+
if (PyImport_ImportOrAddModule("__main__", &main_module) < 0) {
282282
_PyArena_Free(arena);
283283
return -1;
284284
}
@@ -407,9 +407,10 @@ _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit,
407407
{
408408
int ret = -1;
409409

410-
PyObject *main_module = PyImport_AddModuleRef("__main__");
411-
if (main_module == NULL)
410+
PyObject *main_module;
411+
if (PyImport_ImportOrAddModule("__main__", &main_module) < 0) {
412412
return -1;
413+
}
413414
PyObject *dict = PyModule_GetDict(main_module); // borrowed ref
414415

415416
int set_file_name = 0;
@@ -503,8 +504,8 @@ PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit,
503504

504505
int
505506
_PyRun_SimpleStringFlagsWithName(const char *command, const char* name, PyCompilerFlags *flags) {
506-
PyObject *main_module = PyImport_AddModuleRef("__main__");
507-
if (main_module == NULL) {
507+
PyObject *main_module;
508+
if (PyImport_ImportOrAddModule("__main__", &main_module) < 0) {
508509
return -1;
509510
}
510511
PyObject *dict = PyModule_GetDict(main_module); // borrowed ref

0 commit comments

Comments
 (0)