aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Doc/extending
diff options
context:
space:
mode:
Diffstat (limited to 'Doc/extending')
-rw-r--r--Doc/extending/building.rst6
-rw-r--r--Doc/extending/embedding.rst12
-rw-r--r--Doc/extending/extending.rst170
-rw-r--r--Doc/extending/index.rst20
-rw-r--r--Doc/extending/newtypes_tutorial.rst37
5 files changed, 123 insertions, 122 deletions
diff --git a/Doc/extending/building.rst b/Doc/extending/building.rst
index ddde567f6f3..a58eb40d431 100644
--- a/Doc/extending/building.rst
+++ b/Doc/extending/building.rst
@@ -23,10 +23,10 @@ instance. See :ref:`initializing-modules` for details.
.. highlight:: python
For modules with ASCII-only names, the function must be named
-``PyInit_<modulename>``, with ``<modulename>`` replaced by the name of the
-module. When using :ref:`multi-phase-initialization`, non-ASCII module names
+:samp:`PyInit_{<name>}`, with ``<name>`` replaced by the name of the module.
+When using :ref:`multi-phase-initialization`, non-ASCII module names
are allowed. In this case, the initialization function name is
-``PyInitU_<modulename>``, with ``<modulename>`` encoded using Python's
+:samp:`PyInitU_{<name>}`, with ``<name>`` encoded using Python's
*punycode* encoding with hyphens replaced by underscores. In Python::
def initfunc_name(name):
diff --git a/Doc/extending/embedding.rst b/Doc/extending/embedding.rst
index b777862da79..cb41889437c 100644
--- a/Doc/extending/embedding.rst
+++ b/Doc/extending/embedding.rst
@@ -245,21 +245,23 @@ Python extension. For example::
return PyLong_FromLong(numargs);
}
- static PyMethodDef EmbMethods[] = {
+ static PyMethodDef emb_module_methods[] = {
{"numargs", emb_numargs, METH_VARARGS,
"Return the number of arguments received by the process."},
{NULL, NULL, 0, NULL}
};
- static PyModuleDef EmbModule = {
- PyModuleDef_HEAD_INIT, "emb", NULL, -1, EmbMethods,
- NULL, NULL, NULL, NULL
+ static struct PyModuleDef emb_module = {
+ .m_base = PyModuleDef_HEAD_INIT,
+ .m_name = "emb",
+ .m_size = 0,
+ .m_methods = emb_module_methods,
};
static PyObject*
PyInit_emb(void)
{
- return PyModule_Create(&EmbModule);
+ return PyModuleDef_Init(&emb_module);
}
Insert the above code just above the :c:func:`main` function. Also, insert the
diff --git a/Doc/extending/extending.rst b/Doc/extending/extending.rst
index b0493bed75b..fd634956746 100644
--- a/Doc/extending/extending.rst
+++ b/Doc/extending/extending.rst
@@ -203,31 +203,57 @@ function usually raises :c:data:`PyExc_TypeError`. If you have an argument whos
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
-usually declare a static object variable at the beginning of your file::
+You can also define a new exception that is unique to your module.
+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 in your module's initialization function (:c:func:`!PyInit_spam`)
-with an exception object::
+and initialize it by calling :c:func:`PyErr_NewException` in the module's
+:c:data:`Py_mod_exec` function (:c:func:`!spam_module_exec`)::
- PyMODINIT_FUNC
- PyInit_spam(void)
- {
- PyObject *m;
+ SpamError = PyErr_NewException("spam.error", NULL, NULL);
- m = PyModule_Create(&spammodule);
- if (m == NULL)
- return NULL;
+Since :c:data:`!SpamError` is a global variable, it will be overwitten every time
+the module is reinitialized, when the :c:data:`Py_mod_exec` function is called.
+
+For now, let's avoid the issue: 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, "error", SpamError) < 0) {
- Py_CLEAR(SpamError);
- Py_DECREF(m);
- return NULL;
+ if (PyModule_AddObjectRef(m, "SpamError", SpamError) < 0) {
+ return -1;
}
- return m;
+ return 0;
+ }
+
+ static PyModuleDef_Slot spam_module_slots[] = {
+ {Py_mod_exec, spam_module_exec},
+ {0, NULL}
+ };
+
+ static struct PyModuleDef spam_module = {
+ .m_base = PyModuleDef_HEAD_INIT,
+ .m_name = "spam",
+ .m_size = 0, // non-negative
+ .m_slots = spam_module_slots,
+ };
+
+ PyMODINIT_FUNC
+ PyInit_spam(void)
+ {
+ return PyModuleDef_Init(&spam_module);
}
Note that the Python name for the exception object is :exc:`!spam.error`. The
@@ -242,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.
+For now, the :c:func:`Py_DECREF` call to remove this reference is missing.
+Even when the Python interpreter shuts down, the global :c:data:`!SpamError`
+variable 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.
@@ -318,7 +349,7 @@ 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."},
@@ -343,13 +374,10 @@ function.
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
+ static struct PyModuleDef spam_module = {
+ ...
+ .m_methods = spam_methods,
+ ...
};
This structure, in turn, must be passed to the interpreter in the module's
@@ -360,23 +388,17 @@ only non-\ ``static`` item defined in the module file::
PyMODINIT_FUNC
PyInit_spam(void)
{
- return PyModule_Create(&spammodule);
+ return PyModuleDef_Init(&spam_module);
}
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"``.
-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``.
+:c:func:`!PyInit_spam` is called when each interpreter imports its module
+:mod:`!spam` for the first time. (See below for comments about embedding Python.)
+A pointer to the module definition must be returned via :c:func:`PyModuleDef_Init`,
+so that the import machinery can create the module and store it in ``sys.modules``.
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.
@@ -433,23 +455,19 @@ optionally followed by an import of the module::
.. note::
- Removing entries from ``sys.modules`` or importing compiled modules into
- multiple interpreters within a process (or following a :c:func:`fork` without an
- intervening :c:func:`exec`) can create problems for some extension modules.
- Extension module authors should exercise caution when initializing internal data
- structures.
+ If you declare a global variable or a local static one, the module may
+ experience unintended side-effects on re-initialisation, for example when
+ removing entries from ``sys.modules`` or importing compiled modules into
+ multiple interpreters within a process
+ (or following a :c:func:`fork` without an intervening :c:func:`exec`).
+ If module state is not yet fully :ref:`isolated <isolating-extensions-howto>`,
+ authors should consider marking the module as having no support for subinterpreters
+ (via :c:macro:`Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED`).
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 :file:`Modules/xxlimited.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:
@@ -790,18 +808,17 @@ Philbrick (philbrick@hks.com)::
{NULL, NULL, 0, NULL} /* sentinel */
};
- static struct PyModuleDef keywdargmodule = {
- PyModuleDef_HEAD_INIT,
- "keywdarg",
- NULL,
- -1,
- keywdarg_methods
+ static struct PyModuleDef keywdarg_module = {
+ .m_base = PyModuleDef_HEAD_INIT,
+ .m_name = "keywdarg",
+ .m_size = 0,
+ .m_methods = keywdarg_methods,
};
PyMODINIT_FUNC
PyInit_keywdarg(void)
{
- return PyModule_Create(&keywdargmodule);
+ return PyModuleDef_Init(&keywdarg_module);
}
@@ -1072,8 +1089,9 @@ why his :meth:`!__del__` methods would fail...
The second case of problems with a borrowed reference is a variant involving
threads. Normally, multiple threads in the Python interpreter can't get in each
-other's way, because there is a global lock protecting Python's entire object
-space. However, it is possible to temporarily release this lock using the macro
+other's way, because there is a :term:`global lock <global interpreter lock>`
+protecting Python's entire object space.
+However, it is possible to temporarily release this lock using the macro
:c:macro:`Py_BEGIN_ALLOW_THREADS`, and to re-acquire it using
:c:macro:`Py_END_ALLOW_THREADS`. This is common around blocking I/O calls, to
let other threads use the processor while waiting for the I/O to complete.
@@ -1259,20 +1277,15 @@ two more lines must be added::
#include "spammodule.h"
The ``#define`` is used to tell the header file that it is being included in the
-exporting module, not a client module. Finally, the module's initialization
-function must take care of initializing the C API pointer array::
+exporting module, not a client module. Finally, the module's :c:data:`mod_exec
+<Py_mod_exec>` function must take care of initializing the C API pointer array::
- PyMODINIT_FUNC
- PyInit_spam(void)
+ static int
+ spam_module_exec(PyObject *m)
{
- PyObject *m;
static void *PySpam_API[PySpam_API_pointers];
PyObject *c_api_object;
- m = PyModule_Create(&spammodule);
- if (m == NULL)
- return NULL;
-
/* Initialize the C API pointer array */
PySpam_API[PySpam_System_NUM] = (void *)PySpam_System;
@@ -1280,11 +1293,10 @@ function must take care of initializing the C API pointer array::
c_api_object = PyCapsule_New((void *)PySpam_API, "spam._C_API", NULL);
if (PyModule_Add(m, "_C_API", c_api_object) < 0) {
- Py_DECREF(m);
- return NULL;
+ return -1;
}
- return m;
+ return 0;
}
Note that ``PySpam_API`` is declared ``static``; otherwise the pointer
@@ -1343,20 +1355,16 @@ like this::
All that a client module must do in order to have access to the function
:c:func:`!PySpam_System` is to call the function (or rather macro)
-:c:func:`!import_spam` in its initialization function::
+:c:func:`!import_spam` in its :c:data:`mod_exec <Py_mod_exec>` function::
- PyMODINIT_FUNC
- PyInit_client(void)
+ static int
+ client_module_exec(PyObject *m)
{
- PyObject *m;
-
- m = PyModule_Create(&clientmodule);
- if (m == NULL)
- return NULL;
- if (import_spam() < 0)
- return NULL;
+ if (import_spam() < 0) {
+ return -1;
+ }
/* additional initialization can happen here */
- return m;
+ return 0;
}
The main disadvantage of this approach is that the file :file:`spammodule.h` is
diff --git a/Doc/extending/index.rst b/Doc/extending/index.rst
index 01b4df6d44a..4cc2c96d8d5 100644
--- a/Doc/extending/index.rst
+++ b/Doc/extending/index.rst
@@ -26,19 +26,9 @@ Recommended third party tools
=============================
This guide only covers the basic tools for creating extensions provided
-as part of this version of CPython. Third party tools like
-`Cython <https://cython.org/>`_, `cffi <https://cffi.readthedocs.io>`_,
-`SWIG <https://www.swig.org>`_ and `Numba <https://numba.pydata.org/>`_
-offer both simpler and more sophisticated approaches to creating C and C++
-extensions for Python.
-
-.. seealso::
-
- `Python Packaging User Guide: Binary Extensions <https://packaging.python.org/guides/packaging-binary-extensions/>`_
- The Python Packaging User Guide not only covers several available
- tools that simplify the creation of binary extensions, but also
- discusses the various reasons why creating an extension module may be
- desirable in the first place.
+as part of this version of CPython. Some :ref:`third party tools
+<c-api-tools>` offer both simpler and more sophisticated approaches to creating
+C and C++ extensions for Python.
Creating extensions without third party tools
@@ -49,6 +39,10 @@ assistance from third party tools. It is intended primarily for creators
of those tools, rather than being a recommended way to create your own
C extensions.
+.. seealso::
+
+ :pep:`489` -- Multi-phase extension module initialization
+
.. toctree::
:maxdepth: 2
:numbered:
diff --git a/Doc/extending/newtypes_tutorial.rst b/Doc/extending/newtypes_tutorial.rst
index 3fc91841416..f14690de4f8 100644
--- a/Doc/extending/newtypes_tutorial.rst
+++ b/Doc/extending/newtypes_tutorial.rst
@@ -55,8 +55,10 @@ from the previous chapter. This file defines three things:
#. How the :class:`!Custom` **type** behaves: this is the ``CustomType`` struct,
which defines a set of flags and function pointers that the interpreter
inspects when specific operations are requested.
-#. How to initialize the :mod:`!custom` module: this is the ``PyInit_custom``
- function and the associated ``custommodule`` struct.
+#. How to define and execute the :mod:`!custom` module: this is the
+ ``PyInit_custom`` function and the associated ``custom_module`` struct for
+ defining the module, and the ``custom_module_exec`` function to set up
+ a fresh module object.
The first bit is::
@@ -171,18 +173,18 @@ implementation provided by the API function :c:func:`PyType_GenericNew`. ::
.tp_new = PyType_GenericNew,
Everything else in the file should be familiar, except for some code in
-:c:func:`!PyInit_custom`::
+:c:func:`!custom_module_exec`::
- if (PyType_Ready(&CustomType) < 0)
- return;
+ if (PyType_Ready(&CustomType) < 0) {
+ return -1;
+ }
This initializes the :class:`!Custom` type, filling in a number of members
to the appropriate default values, including :c:member:`~PyObject.ob_type` that we initially
set to ``NULL``. ::
if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
- Py_DECREF(m);
- return NULL;
+ return -1;
}
This adds the type to the module dictionary. This allows us to create
@@ -875,27 +877,22 @@ but let the base class handle it by calling its own :c:member:`~PyTypeObject.tp_
The :c:type:`PyTypeObject` struct supports a :c:member:`~PyTypeObject.tp_base`
specifying the type's concrete base class. Due to cross-platform compiler
issues, you can't fill that field directly with a reference to
-:c:type:`PyList_Type`; it should be done later in the module initialization
+:c:type:`PyList_Type`; it should be done in the :c:data:`Py_mod_exec`
function::
- PyMODINIT_FUNC
- PyInit_sublist(void)
+ static int
+ sublist_module_exec(PyObject *m)
{
- PyObject* m;
SubListType.tp_base = &PyList_Type;
- if (PyType_Ready(&SubListType) < 0)
- return NULL;
-
- m = PyModule_Create(&sublistmodule);
- if (m == NULL)
- return NULL;
+ if (PyType_Ready(&SubListType) < 0) {
+ return -1;
+ }
if (PyModule_AddObjectRef(m, "SubList", (PyObject *) &SubListType) < 0) {
- Py_DECREF(m);
- return NULL;
+ return -1;
}
- return m;
+ return 0;
}
Before calling :c:func:`PyType_Ready`, the type structure must have the