I'm writing a C extension for Python that wraps a C library. The C library has a few enum types and I've written corresponding IntEnum
s for these, for example:
from enum import IntEnum
# _enum_consts is a C extension creating Python
# constants for the library's enum constants
from . import _enum_consts
class Align(IntEnum):
DEFAULT = _enum_consts.MD_ALIGN_DEFAULT
LEFT = _enum_consts.MD_ALIGN_LEFT
CENTER = _enum_consts.MD_ALIGN_CENTER
RIGHT = _enum_consts.MD_ALIGN_RIGHT
Now, in the C extension where I'm wrapping the library's main functionality, some of the library functions return enum types, and I want to convert those to the Python IntEnum
values. (I realize I could simply return the int
s directly and they would successfully compare to IntEnum
s, but that sort of defeats the purpose.)
The question is, how do I create the IntEnum
values to return? All I can find are examples where the C enum constants are converted to Python constants with PyModule_AddIntConstant()
(which is just what the _enum_consts
extension module does).
First things first, the module with the IntEnum
needs to be imported into the extension module (if you are not already doing that). In the module initialization function:
PyMODINIT_FUNC PyInit_someextension(void)
{
// ...
PyObject *m;
m = PyModule_Create(&someextension_module);
if (m == NULL) {
return NULL;
}
// ...
// Import the enums module, where "somepackage.enums"
// is the full name of the enums module
PyObject *enums = PyImport_ImportModule("somepackage.enums");
if (enums == NULL) {
Py_DECREF(m);
return NULL;
}
Py_DECREF(enums);
return m;
}
Then, where you want to instantiate an IntEnum
value, first fetch the module it's in again:
PyObject *enums = PyImport_AddModule("somepackage.enums");
if (enums == NULL) {
// Return NULL, -1, etc. to signal an exception
}
Right after, fetch your IntEnum
type (Align
in this case) from the module:
PyObject *align_enum = PyObject_GetAttrString(enums, "Align");
if (align_enum == NULL) {
// Return NULL, -1, etc. to signal an exception
}
Then, you can create the instance you need. align
here will be the value to fetch from the IntEnum
. We do this by calling the type object, just as we would in regular Python (note that PyObject_CallFunction
is not actually limited to calling functions--it can call any callable object):
PyObject *align_instance = PyObject_CallFunction(align_enum, "(i)", align);
if (align_instance == NULL) {
Py_DECREF(align_enum);
// Return NULL, -1, etc. to signal an exception
}
Now, align_instance
contains the IntEnum
instance to return. Be sure to Py_DECREF(align_enum)
before returning.