Over the past few releases the module system has seen great improvements. Kudos to everybody who was involved in the design and implementation of PyModuleDef and multiphase module implementation.
There is one issue, which has not been addressed yet and that has annoying me for years: module level constants. The module API has helpers like PyModule_AddStringConstant
and PyModule_AddStringMacro
, but they are tedious to use. A common problem is also the lack of error checking. Some stdlib modules donāt verify the return values yet.
I came up with a proof of concept for a simpler and more readable approach. The idea is inspired by structmember. Module constants are declared in a new PyModuleConstants_Def array. The array is part of PyModuleDef and initialized by the module initialization framework. The PoC defines a couple of types (int, str, None, boolean, float, function call) and helper macros.
typedef struct PyModuleConstants_Def {
const char *name;
int type;
union {
const char *m_str;
long m_long;
double m_double;
PyObject* (*m_call)(void);
} value;
} PyModuleConstants_Def;
posix module example:
static PyModuleConstants_Def _posix_constants[] = {
#ifdef F_OK
PyMC_LongMacro(F_OK),
#endif
...
{NULL, 0},
};
math module example:
static PyObject*
m_inf_o(void)
{
return PyFloat_FromDouble(m_inf());
}
static PyModuleConstants_Def math_constants[] = {
PyMC_Double("pi", Py_MATH_PI),
PyMC_Double("e", Py_MATH_E),
PyMC_Double("tau", Py_MATH_TAU), // 2pi
PyMC_Call("inf", m_inf_o),
#if !defined(PY_NO_SHORT_FLOAT_REPR) || defined(Py_NAN)
PyMC_Call("nan", m_nan_o),
#endif
{NULL, 0},
};
What do you think about the approach?