Skip to content

Commit 631c02c

Browse files
committed
gh-105922: Add PyImport_AddModuleRef() function
* Add tests on PyImport_AddModuleRef(), PyImport_AddModule() and PyImport_AddModuleObject(). * PyRun_InteractiveOneObjectEx(), _PyRun_SimpleFileObject() and PyRun_SimpleStringFlags() now use PyImport_AddModuleRef() and keep the module strong reference alive longer than before.
1 parent 7a56a41 commit 631c02c

File tree

15 files changed

+203
-49
lines changed

15 files changed

+203
-49
lines changed

Doc/c-api/import.rst

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -98,27 +98,46 @@ Importing Modules
9898
an exception set on failure (the module still exists in this case).
9999
100100
101-
.. c:function:: PyObject* PyImport_AddModuleObject(PyObject *name)
101+
.. c:function:: PyObject* PyImport_AddModuleRef(const char *name)
102+
103+
Return the module object corresponding to a module name.
104+
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.
108+
109+
Return a :term:`strong reference` to the module on success. Return ``NULL``
110+
with an exception set on failure.
111+
112+
The module name *name* is decoded from UTF-8.
113+
114+
This function does not load or import the module; if the module wasn't
115+
already loaded, you will get an empty module object. Use
116+
:c:func:`PyImport_ImportModule` or one of its variants to import a module.
117+
Package structures implied by a dotted name for *name* are not created if
118+
not already present.
102119
103-
Return the module object corresponding to a module name. The *name* argument
104-
may be of the form ``package.module``. First check the modules dictionary if
105-
there's one there, and if not, create a new one and insert it in the modules
106-
dictionary. Return ``NULL`` with an exception set on failure.
120+
.. versionadded:: 3.13
107121
108-
.. note::
109122
110-
This function does not load or import the module; if the module wasn't already
111-
loaded, you will get an empty module object. Use :c:func:`PyImport_ImportModule`
112-
or one of its variants to import a module. Package structures implied by a
113-
dotted name for *name* are not created if not already present.
123+
.. c:function:: PyObject* PyImport_AddModuleObject(PyObject *name)
124+
125+
Similar to :c:func:`PyImport_AddModuleRef`, but return a :term:`borrowed
126+
reference` and *name* is a Python :class:`str` object.
114127
115128
.. versionadded:: 3.3
116129
130+
.. deprecated-removed:: 3.13 3.15
131+
Use :c:func:`PyImport_AddModuleRef` instead.
132+
117133
118134
.. c:function:: PyObject* PyImport_AddModule(const char *name)
119135
120-
Similar to :c:func:`PyImport_AddModuleObject`, but the name is a UTF-8
121-
encoded string instead of a Unicode object.
136+
Similar to :c:func:`PyImport_AddModuleRef`, but return a :term:`borrowed
137+
reference`.
138+
139+
.. deprecated-removed:: 3.13 3.15
140+
Use :c:func:`PyImport_AddModuleRef` instead.
122141
123142
124143
.. c:function:: PyObject* PyImport_ExecCodeModule(const char *name, PyObject *co)

Doc/data/refcounts.dat

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,9 @@ 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+
977980
PyImport_AddModule:PyObject*::0:reference borrowed from sys.modules
978981
PyImport_AddModule:const char*:name::
979982

Doc/data/stable_abi.dat

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

Doc/extending/extending.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -989,9 +989,11 @@ is less clear, here, however, since a few common routines are exceptions:
989989
:c:func:`PyDict_GetItemString` all return references that you borrow from the
990990
tuple, list or dictionary.
991991

992-
The function :c:func:`PyImport_AddModule` also returns a borrowed reference, even
993-
though it may actually create the object it returns: this is possible because an
994-
owned reference to the object is stored in ``sys.modules``.
992+
The deprecated function :c:func:`PyImport_AddModule` also returns a
993+
:term:`borrowed reference`, even though it may actually create the object it
994+
returns: this is possible because an owned reference to the object is stored in
995+
``sys.modules``. The new function :c:func:`PyImport_AddModuleRef` is
996+
recommended since it returns a :term:`strong reference`.
995997

996998
When you pass an object reference into another function, in general, the
997999
function borrows the reference from you --- if it needs to store it, it will use

Doc/whatsnew/3.13.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,11 @@ New Features
426426
APIs accepting the format codes always use ``Py_ssize_t`` for ``#`` formats.
427427
(Contributed by Inada Naoki in :gh:`104922`.)
428428

429+
* Add :c:func:`PyImport_AddModuleRef` function to replace the deprecated
430+
:c:func:`PyImport_AddModule` function: return a :term:`strong reference` to
431+
the module, instead of a :term:`borrowed reference`.
432+
(Contributed by Victor Stinner in :gh:`105922`.)
433+
429434

430435
Porting to Python 3.13
431436
----------------------
@@ -457,6 +462,12 @@ Deprecated
457462
Scheduled for removal in Python 3.15.
458463
(Contributed by Victor Stinner in :gh:`105396`.)
459464

465+
* Deprecate :c:func:`PyImport_AddModule` and :c:func:`PyImport_AddModuleObject`
466+
functions which return a :term:`borrowed reference`. Replace them with the
467+
new :c:func:`PyImport_AddModuleRef` function which returns a :term:`strong
468+
reference`.
469+
(Contributed by Victor Stinner in :gh:`105922`.)
470+
460471
Removed
461472
-------
462473

Include/import.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ PyAPI_FUNC(PyObject *) PyImport_AddModuleObject(
4343
PyAPI_FUNC(PyObject *) PyImport_AddModule(
4444
const char *name /* UTF-8 encoded string */
4545
);
46+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000
47+
PyAPI_FUNC(PyObject *) PyImport_AddModuleRef(
48+
const char *name /* UTF-8 encoded string */
49+
);
50+
#endif
4651
PyAPI_FUNC(PyObject *) PyImport_ImportModule(
4752
const char *name /* UTF-8 encoded string */
4853
);

Lib/test/test_import/__init__.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2621,6 +2621,30 @@ def test_basic_multiple_interpreters_reset_each(self):
26212621
# * module's global state was initialized, not reset
26222622

26232623

2624+
@cpython_only
2625+
class CAPITests(unittest.TestCase):
2626+
def test_pyimport_addmodule(self):
2627+
# gh-105922: Test PyImport_AddModuleRef(), PyImport_AddModule()
2628+
# and PyImport_AddModuleObject()
2629+
import _testcapi
2630+
for name in (
2631+
'sys', # frozen module
2632+
'test', # package
2633+
__name__, # package.module
2634+
):
2635+
_testcapi.check_pyimport_addmodule(name)
2636+
2637+
def test_pyimport_addmodule_create(self):
2638+
# gh-105922: Test PyImport_AddModuleRef(), create a new module
2639+
import _testcapi
2640+
name = 'dontexist'
2641+
self.assertNotIn(name, sys.modules)
2642+
self.addCleanup(unload, name)
2643+
2644+
mod = _testcapi.check_pyimport_addmodule(name)
2645+
self.assertIs(mod, sys.modules[name])
2646+
2647+
26242648
if __name__ == '__main__':
26252649
# Test needs to be a package, so we can do relative imports.
26262650
unittest.main()

Lib/test/test_stable_abi_ctypes.py

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Add :c:func:`PyImport_AddModuleRef` function to replace the deprecated
2+
:c:func:`PyImport_AddModule` function: return a :term:`strong reference` to
3+
the module, instead of a :term:`borrowed reference`. Patch by Victor
4+
Stinner.

Misc/stable_abi.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2428,3 +2428,5 @@
24282428
added = '3.12'
24292429
[const.Py_TPFLAGS_ITEMS_AT_END]
24302430
added = '3.12'
2431+
[function.PyImport_AddModuleRef]
2432+
added = '3.13'

0 commit comments

Comments
 (0)