Skip to content
65 changes: 31 additions & 34 deletions Doc/c-api/module.rst
Original file line number Diff line number Diff line change
Expand Up @@ -479,12 +479,35 @@ state:
.. versionadded:: 3.10


.. c:function:: int PyModule_Add(PyObject *module, const char *name, PyObject *value)

Add an object to *module* as *name*. This is a convenience function which
can be used from the module's initialization function.

On success, return ``0``. On error, raise an exception and return ``-1``.

Return ``-1`` if *value* is ``NULL``. It must be called with an exception
raised in this case.

This function "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.10


.. c:function:: int PyModule_AddObject(PyObject *module, const char *name, PyObject *value)

Similar to :c:func:`PyModule_AddObjectRef`, but steals a reference to
Similar to :c:func:`PyModule_Add`, but only 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` function is recommended, since it is
easy to introduce reference leaks by misusing the
:c:func:`PyModule_AddObject` function.

Expand All @@ -494,41 +517,15 @@ 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``::

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;
}
PyObject *obj = PyBytes_FromString(value);
if (PyModule_AddObject(module, "spam", obj) < 0) {
Py_XDECREF(obj);
goto error;
}

Note that ``Py_XDECREF()`` should be used instead of ``Py_DECREF()`` in
this case, since *obj* can be ``NULL``.
Expand Down
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,10 @@ New Features
success.
(Contributed by Victor Stinner in :issue:`1635741`.)

* Added :c:func:`PyModule_Add` function: similar to
:c:func:`PyModule_AddObject` but always steals a reference to the value.
(Contributed by Serhiy Storchaka in :issue:`42327`.)

* Added :c:func:`Py_NewRef` and :c:func:`Py_XNewRef` functions to increment the
reference count of an object and return the object.
(Contributed by Victor Stinner in :issue:`42262`.)
Expand Down
11 changes: 9 additions & 2 deletions Include/modsupport.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,13 +136,20 @@ PyAPI_FUNC(PyObject * const *) _PyArg_UnpackKeywords(
void _PyArg_Fini(void);
#endif /* Py_LIMITED_API */

#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030A0000
// Add an attribute with name 'name' and value 'value' to the module 'mod'.
// Steal a reference to 'value'.
// On success, return 0.
// On error, raise an exception and return -1.
PyAPI_FUNC(int) PyModule_Add(PyObject *mod, const char *name, PyObject *value);
#endif /* Py_LIMITED_API */

// Add an attribute with name 'name' and value 'obj' to the module 'mod.
// On success, return 0 on success.
// 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).
// Similar to PyModule_Add() but steal a reference to 'value' only on success.
PyAPI_FUNC(int) PyModule_AddObject(PyObject *mod, const char *, PyObject *value);

PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added :func:`PyModule_Add`.
26 changes: 14 additions & 12 deletions Modules/_csv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1642,36 +1642,38 @@ PyInit__csv(void)
/* Add version to the module. */
if (PyModule_AddStringConstant(module, "__version__",
MODULE_VERSION) == -1)
return NULL;
goto error;

/* Set the field limit */
get_csv_state(module)->field_limit = 128 * 1024;
/* Do I still need to add this var to the Module Dict? */

/* Add _dialects dictionary */
get_csv_state(module)->dialects = PyDict_New();
if (get_csv_state(module)->dialects == NULL)
return NULL;
Py_INCREF(get_csv_state(module)->dialects);
if (PyModule_AddObject(module, "_dialects", get_csv_state(module)->dialects))
return NULL;
Py_XINCREF(get_csv_state(module)->dialects);
if (PyModule_Add(module, "_dialects", get_csv_state(module)->dialects))
goto error;

/* Add quote styles into dictionary */
for (style = quote_styles; style->name; style++) {
if (PyModule_AddIntConstant(module, style->name,
style->style) == -1)
return NULL;
goto error;
}

if (PyModule_AddType(module, &Dialect_Type)) {
return NULL;
goto error;
}

/* Add the CSV exception object to the module. */
get_csv_state(module)->error_obj = PyErr_NewException("_csv.Error", NULL, NULL);
if (get_csv_state(module)->error_obj == NULL)
return NULL;
Py_INCREF(get_csv_state(module)->error_obj);
PyModule_AddObject(module, "Error", get_csv_state(module)->error_obj);
Py_XINCREF(get_csv_state(module)->error_obj);
if (PyModule_Add(module, "Error", get_csv_state(module)->error_obj) < 0) {
goto error;
}
return module;

error:
Py_DECREF(module);
return NULL;
}
5 changes: 2 additions & 3 deletions Modules/_curses_panel.c
Original file line number Diff line number Diff line change
Expand Up @@ -668,9 +668,8 @@ _curses_panel_exec(PyObject *mod)
state->PyCursesError = PyErr_NewException(
"_curses_panel.error", NULL, NULL);

Py_INCREF(state->PyCursesError);
if (PyModule_AddObject(mod, "error", state->PyCursesError) < 0) {
Py_DECREF(state->PyCursesError);
Py_XINCREF(state->PyCursesError);
if (PyModule_Add(mod, "error", state->PyCursesError) < 0) {
return -1;
}

Expand Down
Loading