Skip to content
Merged
Show file tree
Hide file tree
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
Diff view
2 changes: 2 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Supported Python versions:
* Python 3.6 - 3.16
* PyPy 3.6 - 3.12

The limited C API is only supported on CPython.

A C11 subset (without optional features) is required, like ``static inline``
functions: see `PEP 7 <https://www.python.org/dev/peps/pep-0007/>`_.

Expand Down
77 changes: 77 additions & 0 deletions tests/extension.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// C extension made of two C files (extension.c and static_inline.c) to detect
// when a pythoncapi_compat.h function is implemented without "static inline".

#ifndef MODULE_NAME
# error "MODULE_NAME macro is not set"
#endif

#include "pythoncapi_compat.h"

#define _STR(NAME) #NAME
#define STR(NAME) _STR(NAME)
#define _CONCAT(a, b) a ## b
#define CONCAT(a, b) _CONCAT(a, b)


// No method and no module exec method needed, most basic C extension


// Use PySlot API on Python 3.15 and newer and on limited C API 3.15 and newer
#if (PY_VERSION_HEX >= _Py_PACK_VERSION(3, 15) \
&& (!defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 15)))

PyABIInfo_VAR(abi_info);

static PySlot module_slots[] = {
PySlot_PTR_STATIC(Py_mod_abi, &abi_info),
PySlot_PTR_STATIC(Py_mod_name, (void*)STR(MODULE_NAME)),
PySlot_PTR_STATIC(Py_mod_state_size, 0),
PySlot_PTR_STATIC(Py_mod_gil, Py_MOD_GIL_NOT_USED),
{0, 0, {0}, {0}}
};

#define EXPORT_FUNC CONCAT(PyModExport_, MODULE_NAME)

PyMODEXPORT_FUNC
EXPORT_FUNC(void)
{
return module_slots;
}

#ifdef MS_WINDOWS
# define INIT_FUNC CONCAT(PyInit_, MODULE_NAME)

// Workaround for https://github.com/pypa/distutils/issues/387
// https://docs.python.org/3.16/howto/abi3t-migration.html#module-export-hook
PyMODINIT_FUNC
INIT_FUNC(void)
{
PyErr_SetString(PyExc_SystemError,
"PyInit_* called for module with PyModExport_*");
return NULL;
}
#endif

#else

static struct PyModuleDef module_def = {
PyModuleDef_HEAD_INIT,
STR(MODULE_NAME), // m_name
_Py_NULL, // m_doc
0, // m_size
_Py_NULL, // m_methods
_Py_NULL, // m_slots
_Py_NULL, // m_traverse
_Py_NULL, // m_clear
_Py_NULL, // m_free
};


#define INIT_FUNC CONCAT(PyInit_, MODULE_NAME)

PyMODINIT_FUNC
INIT_FUNC(void)
{
return PyModule_Create(&module_def);
}
#endif
22 changes: 22 additions & 0 deletions tests/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,28 @@ def add_common_flags(flags, limited):
language='c++')
extensions.append(ext)

# Build a C extension with two C files to detect when a pythoncapi_compat.h
# function is implemented without "static inline".
sources = [
'extension.c',
'static_inline.c',
]
for limited in (False, True):
if limited and not TEST_LIMITED_C_API:
continue
name = 'test_pythoncapi_compat_ext'
assert name != C_EXTENSION_PREFIX
flags = list(COMMON_FLAGS)
if limited:
name += LIMITED_SUFFIX
flags.append(limited_flag)
flags.append(f'-DMODULE_NAME={name}')
ext = Extension(
name,
sources=sources,
extra_compile_args=flags)
extensions.append(ext)

setup(name="test_pythoncapi_compat", ext_modules=extensions)


Expand Down
6 changes: 6 additions & 0 deletions tests/static_inline.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// C extension made of two C files (extension.c and static_inline.c) to detect
// when a pythoncapi_compat.h function is implemented without "static inline".

#include "pythoncapi_compat.h"

// No function defined, only #include "pythoncapi_compat.h"
8 changes: 4 additions & 4 deletions tests/test_pythoncapi_compat_cext.c
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
// Always enable assertions
#undef NDEBUG

#ifndef MODULE_NAME
# error "MODULE_NAME macro is not set"
#endif

#include "pythoncapi_compat.h"
#include <structmember.h> // T_SHORT, READONLY

#ifdef NDEBUG
# error "assertions must be enabled"
#endif

#ifndef MODULE_NAME
# error "MODULE_NAME macro is not set"
#endif

#define _STR(NAME) #NAME
#define STR(NAME) _STR(NAME)
#define _CONCAT(a, b) a ## b
Expand Down
Loading