From f28a09ed54f3f665779a6efda0471d26ab506f99 Mon Sep 17 00:00:00 2001
From: cmoineau <cyril.moineau@cea.fr>
Date: Wed, 24 Jan 2024 16:11:15 +0000
Subject: [PATCH] [PyBind] Add support for setAttrPy for Dynamic and Static
 Attributes.

---
 include/aidge/utils/Attributes.hpp        |  5 +++++
 include/aidge/utils/DynamicAttributes.hpp |  4 ++--
 include/aidge/utils/StaticAttributes.hpp  | 17 ++++++++++++++++-
 python_binding/utils/pybind_Parameter.cpp |  3 ++-
 4 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/include/aidge/utils/Attributes.hpp b/include/aidge/utils/Attributes.hpp
index d34440001..927686cfd 100644
--- a/include/aidge/utils/Attributes.hpp
+++ b/include/aidge/utils/Attributes.hpp
@@ -69,6 +69,11 @@ public:
     *  be agnostic from its return type.
     */
     virtual py::object getAttrPy(const std::string& name) const = 0;
+    /* Bindable set function, does not recquire any templating.
+    *  This is thanks to py::object which allow the function to
+    *  be agnostic from ``value`` type.
+    */
+    virtual void setAttrPy(const std::string& name, py::object&& value) = 0;
 #endif
     virtual ~Attributes() {}
 };
diff --git a/include/aidge/utils/DynamicAttributes.hpp b/include/aidge/utils/DynamicAttributes.hpp
index 2af8f47e9..44c3b1f5e 100644
--- a/include/aidge/utils/DynamicAttributes.hpp
+++ b/include/aidge/utils/DynamicAttributes.hpp
@@ -135,7 +135,7 @@ public:
         assert(res.second && "attribute already exists");
     }
 
-    void setAttrPy(const std::string& name, py::object&& value)
+    void setAttrPy(const std::string& name, py::object&& value) override final
     {
         auto resPy = mAttrsPy.emplace(std::make_pair(name, value));
         if (!resPy.second)
@@ -204,7 +204,7 @@ private:
     // Stores C++ attributes (copy) and Python-only attributes
     // Code should be compiled with -fvisibility=hidden
     // See https://pybind11.readthedocs.io/en/stable/faq.html:
-    // “‘SomeClass’ declared with greater visibility than the type of its 
+    // “‘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;
diff --git a/include/aidge/utils/StaticAttributes.hpp b/include/aidge/utils/StaticAttributes.hpp
index a90a08b01..fa450769f 100644
--- a/include/aidge/utils/StaticAttributes.hpp
+++ b/include/aidge/utils/StaticAttributes.hpp
@@ -212,7 +212,22 @@ public:
         }
 
         AIDGE_THROW_OR_ABORT(py::value_error, "attribute \"%s\" not found", name.c_str());
-    };
+    }
+
+
+    void setAttrPy(const std::string& name, py::object&& value) override final{
+        for (std::size_t i = 0; i < size(EnumStrings<ATTRS_ENUM>::data); ++i) {
+            if (name == EnumStrings<ATTRS_ENUM>::data[i]) {
+                // Cannot update attribute using reference has it would require templating
+                // Use a dirty
+                auto tmpAttr = py::cast(mAttrs);
+                py::detail::accessor_policies::tuple_item::set(tmpAttr, static_cast<py::size_t>(i), value);
+                mAttrs = py::cast<std::tuple<T...>>(tmpAttr);
+                return;
+            }
+        }
+        AIDGE_THROW_OR_ABORT(py::value_error, "attribute \"%s\" not found", name.c_str());
+    }
     #endif
 
 private:
diff --git a/python_binding/utils/pybind_Parameter.cpp b/python_binding/utils/pybind_Parameter.cpp
index 2957876f3..056cbf16b 100644
--- a/python_binding/utils/pybind_Parameter.cpp
+++ b/python_binding/utils/pybind_Parameter.cpp
@@ -21,7 +21,8 @@ void init_Attributes(py::module& m){
     .def("has_attr", &Attributes::hasAttr, py::arg("name"))
     .def("get_attr_type", &Attributes::getAttrType, py::arg("name"))
     .def("get_attrs_name", &Attributes::getAttrsName)
-    .def("get_attr", &Attributes::getAttrPy, py::arg("name"));
+    .def("get_attr", &Attributes::getAttrPy, py::arg("name"))
+    .def("set_attr", &Attributes::setAttrPy, py::arg("name"), py::arg("value"));
 
     py::class_<DynamicAttributes, std::shared_ptr<DynamicAttributes>, Attributes>(m, "DynamicAttributes")
     .def("add_attr", &DynamicAttributes::addAttrPy, py::arg("name"), py::arg("value"))
-- 
GitLab