Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 83ac128

Browse filesBrowse files
bpo-42327: C API: Add PyModule_Add() function (GH-23443)
It is a fixed implementation of PyModule_AddObject() which consistently steals reference both on success and on failure.
1 parent 7454923 commit 83ac128
Copy full SHA for 83ac128

File tree

Expand file treeCollapse file tree

9 files changed

+61
-56
lines changed
Filter options
Expand file treeCollapse file tree

9 files changed

+61
-56
lines changed

‎Doc/c-api/module.rst

Copy file name to clipboardExpand all lines: Doc/c-api/module.rst
+31-34Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -486,12 +486,29 @@ state:
486486
.. versionadded:: 3.10
487487
488488
489+
.. c:function:: int PyModule_Add(PyObject *module, const char *name, PyObject *value)
490+
491+
Similar to :c:func:`PyModule_AddObjectRef`, but "steals" a reference
492+
to *value*.
493+
It can be called with a result of function that returns a new reference
494+
without bothering to check its result or even saving it to a variable.
495+
496+
Example usage::
497+
498+
if (PyModule_Add(module, "spam", PyBytes_FromString(value)) < 0) {
499+
goto error;
500+
}
501+
502+
.. versionadded:: 3.13
503+
504+
489505
.. c:function:: int PyModule_AddObject(PyObject *module, const char *name, PyObject *value)
490506
491507
Similar to :c:func:`PyModule_AddObjectRef`, but steals a reference to
492508
*value* on success (if it returns ``0``).
493509
494-
The new :c:func:`PyModule_AddObjectRef` function is recommended, since it is
510+
The new :c:func:`PyModule_Add` or :c:func:`PyModule_AddObjectRef`
511+
functions are recommended, since it is
495512
easy to introduce reference leaks by misusing the
496513
:c:func:`PyModule_AddObject` function.
497514
@@ -501,44 +518,24 @@ state:
501518
only decrements the reference count of *value* **on success**.
502519
503520
This means that its return value must be checked, and calling code must
504-
:c:func:`Py_DECREF` *value* manually on error.
521+
:c:func:`Py_XDECREF` *value* manually on error.
505522
506523
Example usage::
507524
508-
static int
509-
add_spam(PyObject *module, int value)
510-
{
511-
PyObject *obj = PyLong_FromLong(value);
512-
if (obj == NULL) {
513-
return -1;
514-
}
515-
if (PyModule_AddObject(module, "spam", obj) < 0) {
516-
Py_DECREF(obj);
517-
return -1;
518-
}
519-
// PyModule_AddObject() stole a reference to obj:
520-
// Py_DECREF(obj) is not needed here
521-
return 0;
522-
}
523-
524-
The example can also be written without checking explicitly if *obj* is
525-
``NULL``::
525+
PyObject *obj = PyBytes_FromString(value);
526+
if (PyModule_AddObject(module, "spam", obj) < 0) {
527+
// If 'obj' is not NULL and PyModule_AddObject() failed,
528+
// 'obj' strong reference must be deleted with Py_XDECREF().
529+
// If 'obj' is NULL, Py_XDECREF() does nothing.
530+
Py_XDECREF(obj);
531+
goto error;
532+
}
533+
// PyModule_AddObject() stole a reference to obj:
534+
// Py_XDECREF(obj) is not needed here.
526535
527-
static int
528-
add_spam(PyObject *module, int value)
529-
{
530-
PyObject *obj = PyLong_FromLong(value);
531-
if (PyModule_AddObject(module, "spam", obj) < 0) {
532-
Py_XDECREF(obj);
533-
return -1;
534-
}
535-
// PyModule_AddObject() stole a reference to obj:
536-
// Py_DECREF(obj) is not needed here
537-
return 0;
538-
}
536+
.. deprecated:: 3.13
539537
540-
Note that ``Py_XDECREF()`` should be used instead of ``Py_DECREF()`` in
541-
this case, since *obj* can be ``NULL``.
538+
:c:func:`PyModule_AddObject` is :term:`soft deprecated`.
542539
543540
544541
.. c:function:: int PyModule_AddIntConstant(PyObject *module, const char *name, long value)

‎Doc/data/stable_abi.dat

Copy file name to clipboardExpand all lines: Doc/data/stable_abi.dat
+1Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Doc/whatsnew/3.13.rst

Copy file name to clipboardExpand all lines: Doc/whatsnew/3.13.rst
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,11 @@ New Features
774774
If the assertion fails, make sure that the size is set before.
775775
(Contributed by Victor Stinner in :gh:`106168`.)
776776

777+
* Add :c:func:`PyModule_Add` function: similar to
778+
:c:func:`PyModule_AddObjectRef` and :c:func:`PyModule_AddObject` but
779+
always steals a reference to the value.
780+
(Contributed by Serhiy Storchaka in :gh:`86493`.)
781+
777782
Porting to Python 3.13
778783
----------------------
779784

‎Include/modsupport.h

Copy file name to clipboardExpand all lines: Include/modsupport.h
+9-3Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,18 @@ PyAPI_FUNC(PyObject *) Py_BuildValue(const char *, ...);
2323
PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list);
2424

2525
// Add an attribute with name 'name' and value 'obj' to the module 'mod.
26-
// On success, return 0 on success.
26+
// On success, return 0.
2727
// On error, raise an exception and return -1.
2828
PyAPI_FUNC(int) PyModule_AddObjectRef(PyObject *mod, const char *name, PyObject *value);
2929

30-
// Similar to PyModule_AddObjectRef() but steal a reference to 'obj'
31-
// (Py_DECREF(obj)) on success (if it returns 0).
30+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000
31+
// Similar to PyModule_AddObjectRef() but steal a reference to 'value'.
32+
PyAPI_FUNC(int) PyModule_Add(PyObject *mod, const char *name, PyObject *value);
33+
#endif /* Py_LIMITED_API */
34+
35+
// Similar to PyModule_AddObjectRef() and PyModule_Add() but steal
36+
// a reference to 'value' on success and only on success.
37+
// Errorprone. Should not be used in new code.
3238
PyAPI_FUNC(int) PyModule_AddObject(PyObject *mod, const char *, PyObject *value);
3339

3440
PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long);

‎Lib/test/test_stable_abi_ctypes.py

Copy file name to clipboardExpand all lines: Lib/test/test_stable_abi_ctypes.py
+1Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add :func:`PyModule_Add` function: similar to :c:func:`PyModule_AddObjectRef` and :c:func:`PyModule_AddObject`, but always steals a reference to the value.

‎Misc/stable_abi.toml

Copy file name to clipboardExpand all lines: Misc/stable_abi.toml
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2444,3 +2444,5 @@
24442444
added = '3.13'
24452445
[function.PyMapping_GetOptionalItemString]
24462446
added = '3.13'
2447+
[function.PyModule_Add]
2448+
added = '3.13'

‎PC/python3dll.c

Copy file name to clipboardExpand all lines: PC/python3dll.c
+1Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Python/modsupport.c

Copy file name to clipboardExpand all lines: Python/modsupport.c
+10-19Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -606,13 +606,16 @@ PyModule_AddObjectRef(PyObject *mod, const char *name, PyObject *value)
606606
PyModule_GetName(mod));
607607
return -1;
608608
}
609-
610-
if (PyDict_SetItemString(dict, name, value)) {
611-
return -1;
612-
}
613-
return 0;
609+
return PyDict_SetItemString(dict, name, value);
614610
}
615611

612+
int
613+
PyModule_Add(PyObject *mod, const char *name, PyObject *value)
614+
{
615+
int res = PyModule_AddObjectRef(mod, name, value);
616+
Py_XDECREF(value);
617+
return res;
618+
}
616619

617620
int
618621
PyModule_AddObject(PyObject *mod, const char *name, PyObject *value)
@@ -627,25 +630,13 @@ PyModule_AddObject(PyObject *mod, const char *name, PyObject *value)
627630
int
628631
PyModule_AddIntConstant(PyObject *m, const char *name, long value)
629632
{
630-
PyObject *obj = PyLong_FromLong(value);
631-
if (!obj) {
632-
return -1;
633-
}
634-
int res = PyModule_AddObjectRef(m, name, obj);
635-
Py_DECREF(obj);
636-
return res;
633+
return PyModule_Add(m, name, PyLong_FromLong(value));
637634
}
638635

639636
int
640637
PyModule_AddStringConstant(PyObject *m, const char *name, const char *value)
641638
{
642-
PyObject *obj = PyUnicode_FromString(value);
643-
if (!obj) {
644-
return -1;
645-
}
646-
int res = PyModule_AddObjectRef(m, name, obj);
647-
Py_DECREF(obj);
648-
return res;
639+
return PyModule_Add(m, name, PyUnicode_FromString(value));
649640
}
650641

651642
int

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.