8000 bpo-26515: Update C API docs to use PyModuleDef_Init() by berkerpeksag · Pull Request #8682 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-26515: Update C API docs to use PyModuleDef_Init() #8682

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Changes from all commits
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
8000
Diff view
111 changes: 51 additions & 60 deletions Doc/extending/extending.rst
Original file line number Diff line number Diff line change
Expand Up @@ -204,24 +204,34 @@ usually declare a static object variable at the beginning of your file::

static PyObject *SpamError;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a problem if the module is loaded more than once (for example, in multiple subinterpreters).
In that case, spam_exec would be executed multiple times, each time calling PyErr_NewException and setting SpamError to the newly created error object.

This pointer needs to be part of per-module state.


and initialize it in your module's initialization function (:c:func:`PyInit_spam`)
with an exception object (leaving out the error checking for now)::
and initialize it in a function (:c:func:`spam_exec`) called from a module
execution slot::

PyMODINIT_FUNC
PyInit_spam(void)
static int
spam_exec(PyObject *module)
{
PyObject *m;

m = PyModule_Create(&spammodule);
if (m == NULL)
return NULL;

SpamError = PyErr_NewException("spam.error", NULL, NULL);
if (SpamError == NULL) {
SpamError = PyErr_NewException("spam.error", NULL, NULL);
if (SpamError == NULL) {
goto fail;
}
}
Py_INCREF(SpamError);
PyModule_AddObject(m, "error", SpamError);
return m;
PyModule_AddObject(module, "error", SpamError);
return 0;
fail:
Py_XDECREF(module);
return -1;
}

then we need to specify the :c:func:`spam_exec` function for the
c:var:`Py_mod_exec` slot::
Copy link
10000 Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing the leading : here (that appears to be what the CI error is complaining about)


static struct PyModuleDef_Slot spam_slots[] = {
{Py_mod_exec, spam_exec},
{0, NULL}, /* Sentinel */
};

Note that the Python name for the exception object is :exc:`spam.error`. The
:c:func:`PyErr_NewException` function may create a class with the base class
being :exc:`Exception` (unless another class is passed in instead of *NULL*),
Expand All @@ -234,8 +244,8 @@ 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.

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the modified example, this macro hasn't actually been referenced yet. Instead, the forward reference needs to explain that this list of slots will then be added to a PyModuleDef struct defining the module as a whole, which is described later.

in this sample.

The :exc:`spam.error` exception can be raised in your extension module using a
call to :c:func:`PyErr_SetString` as shown below::
Expand Down Expand Up @@ -291,15 +301,9 @@ on the heap in Python!)

If you have a C function that returns no useful argument (a function returning
:c:type:`void`), the corresponding Python function must return ``None``. You
need this idiom to do so (which is implemented by the :c:macro:`Py_RETURN_NONE`
macro)::

Py_INCREF(Py_None);
return Py_None;
can use the :c:macro:`Py_RETURN_NONE` macro to do so::

:c:data:`Py_None` is the C name for the special Python object ``None``. It is a
genuine Python object rather than a *NULL* pointer, which means "error" in most
contexts, as we have seen.
Py_RETURN_NONE;


.. _methodtable:
Expand All @@ -310,24 +314,21 @@ The Module's Method Table and Initialization Function
I promised to show how :c:func:`spam_system` is called from Python programs.
First, we need to list its name and address in a "method table"::

static PyMethodDef SpamMethods[] = {
...
static PyMethodDef spam_methods[] = {
{"system", spam_system, METH_VARARGS,
"Execute a shell command."},
...
{NULL, NULL, 0, NULL} /* Sentinel */
PyDoc_STR("Execute a shell command.")},
{NULL, NULL} /* Sentinel */
};

Note the third entry (``METH_VARARGS``). This is a flag telling the interpreter
the calling convention to be used for the C function. It should normally always
be ``METH_VARARGS`` or ``METH_VARARGS | METH_KEYWORDS``; a value of ``0`` means
that an obsolete variant of :c:func:`PyArg_ParseTuple` is used.
be ``METH_VARARGS`` or ``METH_VARARGS | METH_KEYWORDS``.

When using only ``METH_VARARGS``, the function should expect the Python-level
When using only :data:`METH_VARARGS`, the function should expect the Python-level
parameters to be passed in as a tuple acceptable for parsing via
:c:func 8000 :`PyArg_ParseTuple`; more information on this function is provided below.

The :const:`METH_KEYWORDS` bit may be set in the third field if keyword
The :data:`METH_KEYWORDS` bit may be set in the third field if keyword
arguments should be passed to the function. In this case, the C function should
accept a third ``PyObject *`` parameter which will be a dictionary of keywords.
Use :c:func:`PyArg_ParseTupleAndKeywords` to parse the arguments to such a
Expand All @@ -337,11 +338,15 @@ The method table must be referenced in the module definition structure::

static struct PyModuleDef spammodule = {
PyModuleDef_HEAD_INIT,
"spam", /* name of module */
spam_doc, /* module documentation, may be NULL */
-1, /* size of per-interpreter state of the module,
or -1 if the module keeps state in global variables. */
SpamMethods
"spam", /* m_name - name of module */
spam_doc, /* m_doc - module documentation, may be NULL */
0, /* m_size - non-negative m_size is required for
multi-phase initialization */
spam_methods, /* m_methods */
spam_slots, /* m_slots - required for multi-phase initialization */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL /* m_free */
};

This structure, in turn, must be passed to the interpreter in the module's
Expand All @@ -352,23 +357,16 @@ only non-\ ``static`` item defined in the module file::
PyMODINIT_FUNC
PyInit_spam(void)
{
return PyModule_Create(&spammodule);
return PyModuleDef_Init(&spammodule);
}

Note that PyMODINIT_FUNC declares the function as ``PyObject *`` return type,
declares any special linkage declarations required by the platform, and for C++
declares the function as ``extern "C"``.

When the Python program imports module :mod:`spam` for the first time,
:c:func:`PyInit_spam` is called. (See below for comments about embedding Python.)
It calls :c:func:`PyModule_Create`, which returns a module object, and
inserts built-in function objects into the newly created module based upon the
table (an array of :c:type:`PyMethodDef` structures) found in the module definition.
:c:func:`PyModule_Create` returns a pointer to the module object
that it creates. It may abort with a fatal error for
certain errors, or return *NULL* if the module could not be initialized
satisfactorily. The init function must return the module object to its caller,
so that it then gets inserted into ``sys.modules``.
Note that :c:macro:`PyMODINIT_FUNC` declares the function as ``PyObject *``
return type, declares any special linkage declarations required by the platform,
and for C++ declares the function as ``extern "C"``.

The initialization function :c:func:`PyInit_spam` returns a :c:type:`PyModuleDef`
instance cast to ``PyObject*`` by calling :c:func:`PyModuleDef_Init`. See
:ref:`multi-phase-initialization` for more information about this process.

When embedding Python, the :c:func:`PyInit_spam` function is not called
automatically unless there's an entry in the :c:data:`PyImport_Inittab` table.
Expand Down Expand Up @@ -413,16 +411,9 @@ optionally followed by an import of the module::
structures.

A more substantial example module is included in the Python source distribution
as :file:`Modules/xxmodule.c`. This file may be used as a template or simply
as :source:`Modules/xxmodule.c`. This file may be used as a template or simply
read as an example.

.. note::

Unlike our ``spam`` example, ``xxmodule`` uses *multi-phase initialization*
(new in Python 3.5), where a PyModuleDef structure is returned from
``PyInit_spam``, and creation of the module is left to the import machinery.
For details on multi-phase initialization, see :PEP:`489`.


.. _compilation:

Expand Down
0