Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

PyBind11 'generic_type: type "" is already registered!' when importing two modules with the same enum

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:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading