I’m importing two modules written in C++ using PyBind11 in my Python program. Both modules A & B export a enum with the same name. I’m importing both to do some testing and comparison.
Their code is like this:
Module A:
PYBIND11_MODULE(module_A, m) {
py::enum_<ENUM_NAME>(m, "ENUM_NAME")
.value("ENUM_VAL1", ENUM_VAL1)
.export_values();
Module B:
PYBIND11_MODULE(module_B, m) {
py::enum_<ENUM_NAME>(m, "ENUM_NAME")
.value("ENUM_VAL2", ENUM_VAL2)
.export_values();
When I import both of them with __import__(module_X) in Python I get this error:
generic_type: type "ENUM_NAME" is already registered!
Why does this happen? The enums are tied to the module right? Why would it matter if two modules have attributes with the same name?
I can of course just rename one, or just import one module at the time but I want to have the flexibility to have any name for any module.
>Solution :
The error "generic_type: type "ENUM_NAME" is already registered!" occurs because PyBind11 registers the enum type globally, even though it is defined within different modules. To avoid this issue, you can encapsulate the enums within a class or a struct.
Here’s two approaches:
1: Encapsulate the enums within a class or struct
For example, in Module A:
struct EnumWrapperA {
enum ENUM_NAME {
ENUM_VAL1
};
};
PYBIND11_MODULE(module_A, m) {
py::class_<EnumWrapperA>(m, "EnumWrapperA")
.def(py::init<>())
.def_readwrite("ENUM_NAME", &EnumWrapperA::ENUM_NAME);
}
And in Module B:
struct EnumWrapperB {
enum ENUM_NAME {
ENUM_VAL2
};
};
PYBIND11_MODULE(module_B, m) {
py::class_<EnumWrapperB>(m, "EnumWrapperB")
.def(py::init<>())
.def_readwrite("ENUM_NAME", &EnumWrapperB::ENUM_NAME);
}
Pros:
Allows you to have enums with the same name in different modules.
Cons:
Requires additional code to define the wrapper class or struct.
2: Combine the modules into a single module
Another approach is to combine the two modules into a single module, as shown in connected pybind11 modules #1391. This way, you can avoid the name conflict altogether.
#include <pybind11/pybind11.h>
namespace py = pybind11;
enum ENUM_NAME_A {
ENUM_VAL1
};
enum ENUM_NAME_B {
ENUM_VAL2
};
PYBIND11_MODULE(combined_module, m) {
py::enum_<ENUM_NAME_A>(m, "ENUM_NAME_A")
.value("ENUM_VAL1", ENUM_VAL1)
.export_values();
py::enum_<ENUM_NAME_B>(m, "ENUM_NAME_B")
.value("ENUM_VAL2", ENUM_VAL2)
.export_values();
}
Pros:
Avoids name conflict by having separate enum names in a single module.
Cons:
Requires combining the modules, which may not be desirable in some cases.