[libgpiod][PATCH 7/9] bindings: python: migrate the gpiod._ext module to multi-phase init

Vincent Fazio
2026-04-22T01:21:03Z

Single-phase initialization has been classified as legacy within CPython
documentation [0] with multi-phase being its successor [1].

As such, switch to the new methodology.

[0]: https://docs.python.org/3/c-api/extension-modules.html#legacy-single-phase-initialization
[1]: https://docs.python.org/3/c-api/extension-modules.html#multi-phase-initialization

Signed-off-by: Vincent Fazio <vfazio@gmail.com>
---
bindings/python/gpiod/ext/module.c | 68 +++++++++++++++---------------
1 file changed, 33 insertions(+), 35 deletions(-)

diff --git a/bindings/python/gpiod/ext/module.c b/bindings/python/gpiod/ext/module.c
index 25c252a..71fa3c2 100644
--- a/bindings/python/gpiod/ext/module.c
+++ b/bindings/python/gpiod/ext/module.c
@@ -135,12 +135,6 @@ static PyMethodDef module_methods[] = {
{ }
};

-static PyModuleDef module_def = {
- PyModuleDef_HEAD_INIT,
- .m_name = "gpiod._ext",
- .m_methods = module_methods,
-};
-
extern PyTypeObject chip_type;
extern PyTypeObject line_config_type;
extern PyTypeObject line_settings_type;
@@ -154,53 +148,57 @@ static PyTypeObject *types[] = {
NULL,
};

-PyMODINIT_FUNC PyInit__ext(void)
+static int module_exec(PyObject* module)
{
const struct module_const *modconst;
- PyObject *module, *all;
+ PyObject *all;
PyTypeObject **type;
int ret;

- module = PyModule_Create(&module_def);
- if (!module)
- return NULL;
-
ret = PyModule_AddStringConstant(module, "api_version",
gpiod_api_version());
- if (ret) {
- Py_DECREF(module);
- return NULL;
- }
+
+ if (ret < 0)
+ return -1;

all = PyList_New(0);
- if (!all) {
- Py_DECREF(module);
- return NULL;
- }
+ if (!all)
+ return -1;

ret = PyModule_AddObjectRef(module, "__all__", all);
Py_DECREF(all);
- if (ret) {
- Py_DECREF(module);
- return NULL;
- }
+ if (ret)
+ return -1;

for (type = types; *type; type++) {
ret = PyModule_AddType(module, *type);
- if (ret) {
- Py_DECREF(module);
- return NULL;
- }
+ if (ret < 0)
+ return -1;
}

for (modconst = module_constants; modconst->name; modconst++) {
- ret = PyModule_AddIntConstant(module,
- modconst->name, modconst->val);
- if (ret) {
- Py_DECREF(module);
- return NULL;
- }
+ ret = PyModule_AddIntConstant(module, modconst->name,
+ modconst->val);
+ if (ret < 0)
+ return -1;
}

- return module;
+ return 0;
+}
+
+static struct PyModuleDef_Slot module_slots[] = {
+ {Py_mod_exec, module_exec},
+ {0, NULL},
+};
+
+static PyModuleDef module_def = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "gpiod._ext",
+ .m_methods = module_methods,
+ .m_slots = module_slots,
+};
+
+PyMODINIT_FUNC PyInit__ext(void)
+{
+ return PyModuleDef_Init(&module_def);
}
--
2.43.0