Skip to content
Snippets Groups Projects
Commit 9e4cdbb9 authored by Olivier BICHLER's avatar Olivier BICHLER
Browse files

Corrected attributes binding

parent 09a9da2f
No related branches found
No related tags found
1 merge request!16Unified interface for attributes
Pipeline #32388 passed with warnings
......@@ -31,7 +31,13 @@ class test_operator_binding(unittest.TestCase):
def test_param_bool(self):
self.generic_operator.add_attr("bool", True)
self.assertEqual(self.generic_operator.has_attr("bool"), True)
self.assertEqual(self.generic_operator.get_attr("bool"), True)
self.assertEqual(self.generic_operator.get_attr_type("bool"), "bool")
self.assertEqual(self.generic_operator.get_attrs_name(), {"bool"})
self.generic_operator.del_attr("bool")
self.assertEqual(self.generic_operator.has_attr("bool"), False)
self.assertEqual(len(self.generic_operator.get_attrs_name()), 0)
def test_param_int(self):
self.generic_operator.add_attr("int", 1)
......
......@@ -58,9 +58,9 @@ public:
/**
* @brief Get the attribute's name list.
* @return std::vector<std::string> Vector of names of the attributes.
* @return std::set<std::string> Vector of names of the attributes.
*/
virtual std::vector<std::string> getAttrsName() const = 0;
virtual std::set<std::string> getAttrsName() const = 0;
#ifdef PYBIND
/* Bindable get function, does not recquire any templating.
......
......@@ -25,6 +25,7 @@
#ifdef PYBIND
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/embed.h>
namespace py = pybind11;
#endif
......@@ -89,8 +90,11 @@ public:
assert(res.second && "attribute already exists");
#ifdef PYBIND
// Keep a copy of the attribute in py::object that is updated everytime
mAttrsPy.emplace(std::make_pair(name, py::cast(value)));
// We cannot handle Python object if the Python interpreter is not running
if (Py_IsInitialized()) {
// Keep a copy of the attribute in py::object that is updated everytime
mAttrsPy.emplace(std::make_pair(name, py::cast(std::forward<T>(value))));
}
#endif
}
......@@ -105,10 +109,20 @@ public:
res.first->second = std::move(libany::any(std::forward<T>(value)));
#ifdef PYBIND
// Keep a copy of the attribute in py::object that is updated everytime
auto resPy = mAttrsPy.emplace(std::make_pair(name, py::cast(value)));
if (!resPy.second)
resPy.first->second = std::move(py::cast(value));
// We cannot handle Python object if the Python interpreter is not running
if (Py_IsInitialized()) {
// Keep a copy of the attribute in py::object that is updated everytime
auto resPy = mAttrsPy.emplace(std::make_pair(name, py::cast(std::forward<T>(value))));
if (!resPy.second)
resPy.first->second = std::move(py::cast(std::forward<T>(value)));
}
#endif
}
void delAttr(const std::string& name) {
mAttrs.erase(name);
#ifdef PYBIND
mAttrsPy.erase(name);
#endif
}
......@@ -131,7 +145,8 @@ public:
//////////////////////////////////////
bool hasAttr(const std::string& name) const override final {
#ifdef PYBIND
return (mAttrsPy.find(name) != mAttrsPy.end());
// Attributes might have been created in Python, the second condition is necessary.
return (mAttrs.find(name) != mAttrs.end() || mAttrsPy.find(name) != mAttrsPy.end());
#else
return (mAttrs.find(name) != mAttrs.end());
#endif
......@@ -155,14 +170,14 @@ public:
return mAttrs.at(name).type().name();
}
std::vector<std::string> getAttrsName() const override final {
std::vector<std::string> attrsName;
std::set<std::string> getAttrsName() const override final {
std::set<std::string> attrsName;
for(auto const& it: mAttrs)
attrsName.insert(it.first);
#ifdef PYBIND
// Attributes might have been created in Python
for(auto const& it: mAttrsPy)
attrsName.push_back(it.first);
#else
for(auto const& it: mAttrs)
attrsName.push_back(it.first);
attrsName.insert(it.first);
#endif
return attrsName;
}
......@@ -185,6 +200,7 @@ private:
// See https://pybind11.readthedocs.io/en/stable/faq.html:
// “‘SomeClass’ declared with greater visibility than the type of its
// field ‘SomeClass::member’ [-Wattributes]”
// This map will only be populated if Python interpreter is running
std::map<std::string, py::object> mAttrsPy;
// Stores C++ attributes only
// mutable because it may be updated in getAttr() from Python
......
......@@ -162,10 +162,10 @@ public:
assert(false && "attribute not found");
}
std::vector<std::string> getAttrsName() const override final {
std::vector<std::string> attrsName;
std::set<std::string> getAttrsName() const override final {
std::set<std::string> attrsName;
for (std::size_t i = 0; i < size(EnumStrings<ATTRS_ENUM>::data); ++i) {
attrsName.push_back(EnumStrings<ATTRS_ENUM>::data[i]);
attrsName.insert(EnumStrings<ATTRS_ENUM>::data[i]);
}
return attrsName;
}
......
......@@ -13,7 +13,8 @@ void init_Attributes(py::module& m){
py::class_<DynamicAttributes, std::shared_ptr<DynamicAttributes>, Attributes>(m, "DynamicAttributes")
.def("add_attr", &DynamicAttributes::addAttrPy, py::arg("name"), py::arg("value"))
.def("set_attr", &DynamicAttributes::setAttrPy, py::arg("name"), py::arg("value"));
.def("set_attr", &DynamicAttributes::setAttrPy, py::arg("name"), py::arg("value"))
.def("del_attr", &DynamicAttributes::delAttr, py::arg("name"));
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment