pybind / pybind11

Seamless operability between C++11 and Python
https://pybind11.readthedocs.io/
Other
15.5k stars 2.09k forks source link

Unable to assign to python property #2871

Open jjcasmar opened 3 years ago

jjcasmar commented 3 years ago

I am trying to export an enum and a property for a class which uses the enum. In my class I have this two methods

ForcesMap forcesMap() const; //getter
void setForcesMap(const VNCS::Sim2D::DeformationGradientMap::ForcesMap &forcesMap); //setter

the enum is defined in the scope of my class

enum class ForcesMap { Coarse, Fine };

I create bindings for both the enum and the class like this

::py::enum_<VNCS::Sim2D::DeformationGradientMap::ForcesMap>(m, "ForcesMap")
        .value("Coarse", VNCS::Sim2D::DeformationGradientMap::ForcesMap::Coarse)
        .value("Fine", VNCS::Sim2D::DeformationGradientMap::ForcesMap::Fine);

::py::class_<VNCS::Sim2D::DeformationGradientMap, Inherit, sofa::core::sptr<VNCS::Sim2D::DeformationGradientMap>>(
        m, "DeformationGradientMap")
        ...
        .def_property("forcesMap",
                      &VNCS::Sim2D::DeformationGradientMap::forcesMap,
                      &VNCS::Sim2D::DeformationGradientMap::setForcesMap);

The getter works fine. I am able to read the property from python and when debugging, it stop in a breakpoint inside the getter. However, the setter doesn't work, it is never called.

From python, I can do the following:

dir(PyVNCS.Sim2D.ForcesMap)
['Coarse', 'Fine', '__class__', '__delattr__', '__dir__', '__doc__', '__entries', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', ...]
phiFMap.forcesMap
<ForcesMap.Coarse: 0>
phiFMap.forcesMap = PyVNCS.Sim2D.ForcesMap.Fine
phiFMap.forcesMap
<ForcesMap.Coarse: 0>

However, it works fine if I change to a readonly property + a function which sets the value (.def_property_readonly + .def)

bstaletic commented 3 years ago

Works fine for me. You'll have to give more context and provide a minimal example.

#include <pybind11/pybind11.h>
enum class E { a, b };
struct s {
    E e;
    auto get() const { return e; }
    auto set(E e_) { e = e_; }
};

PYBIND11_MODULE(foo, m) {
    pybind11::enum_<E>(m, "E").value("a", E::a).value("b", E::b);
    pybind11::class_<s>(m, "s").def_property("e", &s::get, &s::set).def(pybind11::init<>());
}
>>> import foo
>>> f=foo.s()
>>> f
<foo.s object at 0x7f0d2aa465b0>
>>> f.e
<E.a: 0>
>>> f.e=foo.E.b
>>> f.e
<E.b: 1>