Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions Doc/extending/extending.rst
Original file line number Diff line number Diff line change
Expand Up @@ -204,17 +204,32 @@ value must be in a particular range or must satisfy other conditions,
:c:data:`PyExc_ValueError` is appropriate.

You can also define a new exception that is unique to your module.
For this, you can declare a static global object variable at the beginning
of the file::
The simplest way to do this is to declare a static global object variable at
the beginning of the file::

static PyObject *SpamError;
static PyObject *SpamError = NULL;

and initialize it with an exception object in the module's
and initialize it by calling :c:func:`PyErr_NewException` in the module's
:c:data:`Py_mod_exec` function (:c:func:`!spam_module_exec`)::

SpamError = PyErr_NewException("spam.error", NULL, NULL);

Since :c:data:`!SpamError` is a global variable, each call to the
:c:data:`Py_mod_exec` function would overwrite it.
It is not very common to load multiple copies of a module, so for now,
we will block repeated initialization by raising an
:py:exc:`ImportError`::

static PyObject *SpamError = NULL;

static int
spam_module_exec(PyObject *m)
{
if (SpamError != NULL) {
PyErr_SetString(PyExc_ImportError,
"cannot initialize spam module more than once");
return -1;
}
SpamError = PyErr_NewException("spam.error", NULL, NULL);
if (PyModule_AddObjectRef(m, "SpamError", SpamError) < 0) {
return -1;
Expand Down Expand Up @@ -253,6 +268,11 @@ needed to ensure that it will not be discarded, causing :c:data:`!SpamError` to
become a dangling pointer. Should it become a dangling pointer, C code which
raises the exception could cause a core dump or other unintended side effects.

Also note that there is no :c:func:`Py_DECREF` call to remove this reference.
Even when the Python interpreter shuts down, :c:data:`!SpamError` will not be
garbage-collected. It will "leak".
We did, however, ensure that this will happen at most once per process.

We discuss the use of :c:macro:`PyMODINIT_FUNC` as a function return type later in this
sample.

Expand Down
Loading