Skip to content

What about enumerations? #59

@barnou-psee

Description

@barnou-psee

Hi,

I must say I really like the idea of this utility to ease my parameters structures usage in Python. I encountered an issue with bound enumerations. I use enumerations quite a lot in C++ mainly in factories. I can easily have a nlohmann converters for them, I can easily bind them, but I'm lost when trying to have the two functionalities working together.

It's quite logic since the nlohmann json bindings expect classic types and I guess enumerations fall into a special structures. I tried to get how I could handle those errors but I struggle finding how I could do that.

module.cpp

#include 

#include "nlohmann/json.hpp"
// This is where I copied pybind11_json.hpp
#include "converters/json.h"

#define MODULE_NAME footest

namespace testing_pybind11_json {

enum class Foo : uint32_t { ZERO, ONE, TWO, THREE };
NLOHMANN_JSON_SERIALIZE_ENUM(Foo,
{{Foo::ZERO, "ZERO"},
{Foo::ONE, "ONE"},
{Foo::TWO, "TWO"},
{Foo::THREE, "THREE"}})

void print_json(const nlohmann::json &j) {
std::cout << std::endl << std::setw(4) << j.dump() << std::endl;
}

void print_dict(const py::dict &d) {
nlohmann::json j;
j = d;
std::cout << std::endl << std::setw(4) << j.dump() << std::endl;
}

} // namespace testing_pybind11_json

PYBIND11_MODULE(MODULE_NAME, m) {
Py_Initialize();
PyEval_InitThreads();

py::enum_<testing_pybind11_json::Foo>(m, "Foo")
    .value("ZERO", testing_pybind11_json::Foo::ZERO)
    .value("ONE", testing_pybind11_json::Foo::ONE)
    .value("TWO", testing_pybind11_json::Foo::TWO)
    .value("THREE", testing_pybind11_json::Foo::THREE);
m.def("print_json", &testing_pybind11_json::print_json);
m.def("print_dict", &testing_pybind11_json::print_dict);

}

footest_pytest.cpp

import footest
import pytest

@pytest.mark.module("binding.utils")
def pytestcase_testing_pybind11_print_json():
footest.print_json({'a': 1, 'b': 2})
footest.print_json({'a': 1, 'b': 2, 'c': footest.Foo.ONE})

@pytest.mark.module("binding.utils")
def pytestcase_testing_pybind11_print_dict():
footest.print_dict({'a': 1, 'b': 2})
footest.print_dict({'a': 1, 'b': 2, 'c': footest.Foo.ONE})

It returns me different type of error depending on the function I'm using.

With print_json: it tries to use directly type_caster but seems to fall in a strange case.

    @pytest.mark.module("binding.utils")
    def pytestcase_testing_pybind11_print_json():
        mci.print_json({'a': 1, 'b': 2})
>       mci.print_json({'a': 1, 'b': 2, 'c': mci.Foo.ONE})
E       TypeError: print_json(): incompatible function arguments. The following argument types are supported:
E           1. (arg0: json) -> None
E       
E       Invoked with: {'a': 1, 'b': 2, 'c': <Foo.ONE: 1>}

sdk/modules/computational_imaging/python/tests/bindings/calibration_pytest.py:148: TypeError

With print_dict: I avoid using type_caster but calls directly the to_json function which goes well until the incompatible enum.

    @pytest.mark.module("binding.utils")
    def pytestcase_testing_pybind11_print_dict():
        mci.print_dict({'a': 1, 'b': 2})
>       mci.print_dict({'a': 1, 'b': 2, 'c': mci.Foo.ONE})
E       RuntimeError: to_json not implemented for this type of object: <Foo.ONE: 1>

sdk/modules/computational_imaging/python/tests/bindings/calibration_pytest.py:154: RuntimeError

I don't know if it's even possible to catch the enumeration case and call the to_json / from_json of the underlying enumeration.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions