I would like to wrap the following code in cython:
enum Status {GOOD, BAD};
typedef enum Status STATUS;
// note that the typedef means people dont
// have to write `enum Status` everywhere
// just returns `GOOD`
STATUS hello();
I wrote the following cython code in c_library.pxd
:
cdef extern from "library.h":
cpdef enum Status:
GOOD,
BAD
ctypedef Status STATUS
cpdef STATUS hello()
The module c_library
now contains c_library.GOOD
, c_library.BAD
,
and c_library.Status
, which behaves like an enum. However, the
return value of a call to function hello
returns a plain int:
>>> c_library.hello()
0
>>> type(c_library.hello())
<class 'int'>
I would like the result to be wrapped in an enum of the same type as well.
I can change the cython file, but not the underlying C code. Is that possible?
That looks like a hiccup (minor bug?) of Cython, which decides to use __Pyx_PyInt_From_enum__
for some reasons when wrapping cdef
-function into a def
function.
As a quick workaround I can propose to explicitly create a Status
-enum:
%%cython
cdef extern from *:
"""
typedef enum Status {GOOD, BAD} Status;
// just returns `GOOD`
Status hello() {return GOOD;}
"""
cpdef enum Status:
GOOD,
BAD
Status c_hello "hello"()
def hello():
return Status(c_hello())
And now:
>>> type(hello())
<enum 'Status'>
Things maybe worth noting:
- verbatim C-code is used, to make the example self-contained.
- Using
typedef enum X {...} X;
to pull enum's type-name from enum's name space into the name space of ordinary variables is a common practice (but obviously this is a matter of taste, so if you prefer STATUS
- it is up to you). See the wording in C11-standard on different name spaces here or this great answer (even if it is about struct
).
cname
-trick (i.e. Status c_hello "hello"()
) is used, to be able to add a level of indirection and to keep the public interface of the module intact (i.e. cpdef hello()
).
- However, when using
hello
as cdef
-function I would probably use c_hello
to avoid overhead of creating an enum - that is the reason hello()
is defined as a def
-function, so there is no confusion.