summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/c-api/module.rst65
-rw-r--r--Doc/data/stable_abi.dat1
-rw-r--r--Doc/whatsnew/3.13.rst5
-rw-r--r--Include/modsupport.h12
-rw-r--r--Lib/test/test_stable_abi_ctypes.py1
-rw-r--r--Misc/NEWS.d/next/C API/2020-11-11-22-36-29.bpo-42327.ODSZBM.rst1
-rw-r--r--Misc/stable_abi.toml2
-rwxr-xr-xPC/python3dll.c1
-rw-r--r--Python/modsupport.c29
9 files changed, 61 insertions, 56 deletions
diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst
index 230b471..d35b302 100644
--- a/Doc/c-api/module.rst
+++ b/Doc/c-api/module.rst
@@ -486,12 +486,29 @@ state:
.. versionadded:: 3.10
+.. c:function:: int PyModule_Add(PyObject *module, const char *name, PyObject *value)
+
+ Similar to :c:func:`PyModule_AddObjectRef`, but "steals" a reference
+ to *value*.
+ It can be called with a result of function that returns a new reference
+ without bothering to check its result or even saving it to a variable.
+
+ Example usage::
+
+ if (PyModule_Add(module, "spam", PyBytes_FromString(value)) < 0) {
+ goto error;
+ }
+
+ .. versionadded:: 3.13
+
+
.. c:function:: int PyModule_AddObject(PyObject *module, const char *name, PyObject *value)
Similar to :c:func:`PyModule_AddObjectRef`, but steals a reference to
*value* on success (if it returns ``0``).
- The new :c:func:`PyModule_AddObjectRef` function is recommended, since it is
+ The new :c:func:`PyModule_Add` or :c:func:`PyModule_AddObjectRef`
+ functions are recommended, since it is
easy to introduce reference leaks by misusing the
:c:func:`PyModule_AddObject` function.
@@ -501,44 +518,24 @@ state:
only decrements the reference count of *value* **on success**.
This means that its return value must be checked, and calling code must
- :c:func:`Py_DECREF` *value* manually on error.
+ :c:func:`Py_XDECREF` *value* manually on error.
Example usage::
- static int
- add_spam(PyObject *module, int value)
- {
- PyObject *obj = PyLong_FromLong(value);
- if (obj == NULL) {
- return -1;
- }
- if (PyModule_AddObject(module, "spam", obj) < 0) {
- Py_DECREF(obj);
- return -1;
- }
- // PyModule_AddObject() stole a reference to obj:
- // Py_DECREF(obj) is not needed here
- return 0;
- }
-
- The example can also be written without checking explicitly if *obj* is
- ``NULL``::
+ PyObject *obj = PyBytes_FromString(value);
+ if (PyModule_AddObject(module, "spam", obj) < 0) {
+ // If 'obj' is not NULL and PyModule_AddObject() failed,
+ // 'obj' strong reference must be deleted with Py_XDECREF().
+ // If 'obj' is NULL, Py_XDECREF() does nothing.
+ Py_XDECREF(obj);
+ goto error;
+ }
+ // PyModule_AddObject() stole a reference to obj:
+ // Py_XDECREF(obj) is not needed here.
- static int
- add_spam(PyObject *module, int value)
- {
- PyObject *obj = PyLong_FromLong(value);
- if (PyModule_AddObject(module, "spam", obj) < 0) {
- Py_XDECREF(obj);
- return -1;
- }
- // PyModule_AddObject() stole a reference to obj:
- // Py_DECREF(obj) is not needed here
- return 0;
- }
+ .. deprecated:: 3.13
- Note that ``Py_XDECREF()`` should be used instead of ``Py_DECREF()`` in
- this case, since *obj* can be ``NULL``.
+ :c:func:`PyModule_AddObject` is :term:`soft deprecated`.
.. c:function:: int PyModule_AddIntConstant(PyObject *module, const char *name, long value)
diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat
index e3dd3da..aa1edf5 100644
--- a/Doc/data/stable_abi.dat
+++ b/Doc/data/stable_abi.dat
@@ -399,6 +399,7 @@ type,PyModuleDef,3.2,,full-abi
type,PyModuleDef_Base,3.2,,full-abi
function,PyModuleDef_Init,3.5,,
var,PyModuleDef_Type,3.5,,
+function,PyModule_Add,3.13,,
function,PyModule_AddFunctions,3.7,,
function,PyModule_AddIntConstant,3.2,,
function,PyModule_AddObject,3.2,,
diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index 161d5fb..0181e16 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -774,6 +774,11 @@ New Features
If the assertion fails, make sure that the size is set before.
(Contributed by Victor Stinner in :gh:`106168`.)
+* Add :c:func:`PyModule_Add` function: similar to
+ :c:func:`PyModule_AddObjectRef` and :c:func:`PyModule_AddObject` but
+ always steals a reference to the value.
+ (Contributed by Serhiy Storchaka in :gh:`86493`.)
+
Porting to Python 3.13
----------------------
diff --git a/Include/modsupport.h b/Include/modsupport.h
index 7d4cfe8..51061c5 100644
--- a/Include/modsupport.h
+++ b/Include/modsupport.h
@@ -23,12 +23,18 @@ PyAPI_FUNC(PyObject *) Py_BuildValue(const char *, ...);
PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list);
// Add an attribute with name 'name' and value 'obj' to the module 'mod.
-// On success, return 0 on success.
+// On success, return 0.
// On error, raise an exception and return -1.
PyAPI_FUNC(int) PyModule_AddObjectRef(PyObject *mod, const char *name, PyObject *value);
-// Similar to PyModule_AddObjectRef() but steal a reference to 'obj'
-// (Py_DECREF(obj)) on success (if it returns 0).
+#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030d0000
+// Similar to PyModule_AddObjectRef() but steal a reference to 'value'.
+PyAPI_FUNC(int) PyModule_Add(PyObject *mod, const char *name, PyObject *value);
+#endif /* Py_LIMITED_API */
+
+// Similar to PyModule_AddObjectRef() and PyModule_Add() but steal
+// a reference to 'value' on success and only on success.
+// Errorprone. Should not be used in new code.
PyAPI_FUNC(int) PyModule_AddObject(PyObject *mod, const char *, PyObject *value);
PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long);
diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py
index e92e986..4e74bb3 100644
--- a/Lib/test/test_stable_abi_ctypes.py
+++ b/Lib/test/test_stable_abi_ctypes.py
@@ -425,6 +425,7 @@ SYMBOL_NAMES = (
"PyMethodDescr_Type",
"PyModuleDef_Init",
"PyModuleDef_Type",
+ "PyModule_Add",
"PyModule_AddFunctions",
"PyModule_AddIntConstant",
"PyModule_AddObject",
diff --git a/Misc/NEWS.d/next/C API/2020-11-11-22-36-29.bpo-42327.ODSZBM.rst b/Misc/NEWS.d/next/C API/2020-11-11-22-36-29.bpo-42327.ODSZBM.rst
new file mode 100644
index 0000000..3d935ac
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2020-11-11-22-36-29.bpo-42327.ODSZBM.rst
@@ -0,0 +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.
diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml
index 8ea8fde..dd2c991 100644
--- a/Misc/stable_abi.toml
+++ b/Misc/stable_abi.toml
@@ -2444,3 +2444,5 @@
added = '3.13'
[function.PyMapping_GetOptionalItemString]
added = '3.13'
+[function.PyModule_Add]
+ added = '3.13'
diff --git a/PC/python3dll.c b/PC/python3dll.c
index 8f2df69..0b54c5a 100755
--- a/PC/python3dll.c
+++ b/PC/python3dll.c
@@ -374,6 +374,7 @@ EXPORT_FUNC(PyMemoryView_FromBuffer)
EXPORT_FUNC(PyMemoryView_FromMemory)
EXPORT_FUNC(PyMemoryView_FromObject)
EXPORT_FUNC(PyMemoryView_GetContiguous)
+EXPORT_FUNC(PyModule_Add)
EXPORT_FUNC(PyModule_AddFunctions)
EXPORT_FUNC(PyModule_AddIntConstant)
EXPORT_FUNC(PyModule_AddObject)
diff --git a/Python/modsupport.c b/Python/modsupport.c
index 3db95f1..18b3322 100644
--- a/Python/modsupport.c
+++ b/Python/modsupport.c
@@ -606,13 +606,16 @@ PyModule_AddObjectRef(PyObject *mod, const char *name, PyObject *value)
PyModule_GetName(mod));
return -1;
}
-
- if (PyDict_SetItemString(dict, name, value)) {
- return -1;
- }
- return 0;
+ return PyDict_SetItemString(dict, name, value);
}
+int
+PyModule_Add(PyObject *mod, const char *name, PyObject *value)
+{
+ int res = PyModule_AddObjectRef(mod, name, value);
+ Py_XDECREF(value);
+ return res;
+}
int
PyModule_AddObject(PyObject *mod, const char *name, PyObject *value)
@@ -627,25 +630,13 @@ PyModule_AddObject(PyObject *mod, const char *name, PyObject *value)
int
PyModule_AddIntConstant(PyObject *m, const char *name, long value)
{
- PyObject *obj = PyLong_FromLong(value);
- if (!obj) {
- return -1;
- }
- int res = PyModule_AddObjectRef(m, name, obj);
- Py_DECREF(obj);
- return res;
+ return PyModule_Add(m, name, PyLong_FromLong(value));
}
int
PyModule_AddStringConstant(PyObject *m, const char *name, const char *value)
{
- PyObject *obj = PyUnicode_FromString(value);
- if (!obj) {
- return -1;
- }
- int res = PyModule_AddObjectRef(m, name, obj);
- Py_DECREF(obj);
- return res;
+ return PyModule_Add(m, name, PyUnicode_FromString(value));
}
int