Wrap enum class for cython
CPP class
enum class Color {red, green = 20, blue};
Definition of type
cdef extern from "colors.h":
cdef cppclass Color:
pass
Definition of color types
cdef extern from "colors.h" namespace "Color":
cdef Color red
cdef Color green
cdef Color blue
Python implementation
cdef class PyColor:
cdef Color thisobj
def __cinit__(self, int val):
self.thisobj = <Color> val
def get_color_type(self):
cdef c = {<int>red : "red", <int> green : "green", <int> blue : "blue"}
return c[<int>self.thisobj]
Another alternative that allows using PEP-435 Enums as mentioned in Cython docs is as follows:
foo.h
namespace foo {
enum class Bar : uint32_t {
Zero = 0,
One = 1
};
}
foo.pxd
from libc.stdint cimport uint32_t
cdef extern from "foo.h" namespace 'foo':
cdef enum _Bar 'foo::Bar':
_Zero 'foo::Bar::Zero'
_One 'foo::Bar::One'
cpdef enum Bar:
Zero = <uint32_t> _Zero
One = <uint32_t> _One
main.pyx
from foo cimport Bar
print(Bar.Zero)
print(Bar.One)
# or iterate over elements
for value in Bar:
print(value)
Here's an alternative solution that uses the ability to change the name of cython and C++ identifiers.
header.hpp
namespace foo {
enum class Bar : uint32_t {
BAZ,
QUUX
};
}
header.pxd
cdef extern from "header.hpp" namespace "foo::Bar":
cdef enum Bar "foo::Bar":
BAZ,
QUUX
main.pyx
from header cimport *
cdef void doit(Bar b):
pass
doit(BAZ) # Not Bar.BAZ, which would have been nicer.
It's effectively telling cython that there exists a namespace called "foo::Bar", and puts a C-style enum in it. To counteract the fact that Bar would otherwise become "foo::Bar::Bar" that is also given an overridden name. It does mean that Bar::BAZ is referred to as BAZ in cython, rather than Bar.BAZ which would be a more idiomatic representation of enum classes, but it seems close enough.