Skip to content

Commit

Permalink
Merge pull request #198 from CRIStAL-PADR/pr-add-createobject-behavior
Browse files Browse the repository at this point in the history
[SofaPython3] Changes how addObject process its arguments when they are of type: numpy & data
  • Loading branch information
damienmarchal committed Nov 3, 2021
2 parents f1140e9 + 44dbe9c commit 166f7f5
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 4 deletions.
10 changes: 9 additions & 1 deletion Plugin/src/SofaPython3/DataHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,20 @@ std::string toSofaParsableString(const py::handle& p)
if(py::isinstance<py::str>(p))
return py::str(p);

// Insure compatibility with data field code returning value instead of data.
// If the object is a data field we link the data field
if(py::isinstance<sofa::core::objectmodel::BaseData>(p))
{
sofa::core::objectmodel::BaseData* data = py::cast<sofa::core::objectmodel::BaseData*>(p);
return data->getValueString();
}

// If the object is a numpy array we convert it to a list then to a sofa string.
if(py::isinstance<py::array>(p))
{
py::object o = p.attr("tolist")();
return toSofaParsableString(o);
}

return py::repr(p);
}

Expand Down
11 changes: 9 additions & 2 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,13 @@ std::string BindingBase::getPathName(Base& self)
{
return self.toBaseNode() ? self.toBaseNode()->getPathName() : self.toBaseObject()->getPathName();
}


std::string BindingBase::getLinkPath(Base& self)
{
return "@"+getPathName(self);
}


py::object BindingBase::setDataValues(Base& self, py::kwargs kwargs)
{
for(auto key : kwargs)
Expand Down Expand Up @@ -435,7 +441,8 @@ void moduleAddBase(py::module &m)
base.def("getLoggedMessagesAsString", &BindingBase::getLoggedMessagesAsString, sofapython3::doc::base::getLoggedMessagesAsString);
base.def("countLoggedMessages", &BindingBase::countLoggedMessages, sofapython3::doc::base::countLoggedMessages);
base.def("clearLoggedMessages", &BindingBase::clearLoggedMessages, sofapython3::doc::base::clearLoggedMessages);
base.def("getPathName", &BindingBase::getPathName);
base.def("getPathName", &BindingBase::getPathName, sofapython3::doc::base::getPathName);
base.def("getLinkPath", &BindingBase::getLinkPath, sofapython3::doc::base::getLinkPath);
base.def("setDataValues", &BindingBase::setDataValues, sofapython3::doc::base::setDataValues);
}

Expand Down
1 change: 1 addition & 0 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class BindingBase
static pybind11::object countLoggedMessages(sofa::core::objectmodel::Base& self);
static pybind11::object clearLoggedMessages(sofa::core::objectmodel::Base& self);
static std::string getPathName(sofa::core::objectmodel::Base& self);
static std::string getLinkPath(sofa::core::objectmodel::Base& self);
};


Expand Down
4 changes: 4 additions & 0 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ py::object writeableArray(BaseData* self)

void __setattr__(py::object self, const std::string& s, py::object value)
{
SOFA_UNUSED(s);
BaseData* selfdata = py::cast<BaseData*>(self);

if(py::isinstance<DataContainer>(value))
Expand All @@ -137,6 +138,9 @@ py::object __getattr__(py::object self, const std::string& s)
if(s == "value")
return PythonFactory::valueToPython_ro(py::cast<BaseData*>(self));

if(s == "linkpath")
return py::cast((py::cast<BaseData*>(self))->getLinkPath());

/// BaseData does not support dynamic attributes, if you think this is an important feature
/// please request for its integration.
throw py::attribute_error("There is no attribute '"+s+"'");
Expand Down
16 changes: 16 additions & 0 deletions bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base_doc.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,22 @@ static auto findData =
:type name: string
:return: the data field
)";
static auto getLinkPath =
R"(
returns the path name as a parsable string.
eg:
if object.getPathName() is "/child1/object"
then the linkPath is @"/child1/object"
)";
static auto getPathName =
R"(
returns the path name as a string.
.. code-block:: python
a = Sofa.Core.Node("root")
b.addObject("Camera", name="camera")
b.getPathName() # should returns "/root/camera"
```
)";
static auto setDataValues =
R"(
Set values for a the given data field, multiple pairs of args are allowed.
Expand Down
6 changes: 5 additions & 1 deletion bindings/Sofa/tests/Core/Base.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,11 @@ def test_getTemplateName(self):
c = root.addObject("MechanicalObject", name="t")
self.assertEqual(c.getTemplateName(),"Vec3d")


def test_getLinkPath(self):
root = create_scene("root")
obj = root.addObject("MechanicalObject", name="obj")
self.assertEqual(obj.getPathName(),"/obj")
self.assertEqual(obj.getLinkPath(),"@/obj")

def test_addExistingDataAsParentOfNewData(self):
# TODO(@marques-bruno)
Expand Down
5 changes: 5 additions & 0 deletions bindings/Sofa/tests/Core/BaseData.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,11 @@ def t(c):
self.assertEqual(wa[2, 2], 8.0)
numpy.testing.assert_array_equal(wa, v*4.0)

def test_linkpath(self):
n = create_scene("rootNode")
m = n. addObject("MechanicalObject", name="dofs")
self.assertEqual(m.position.linkpath, "@/dofs.position")

def test_set_value_from_string(self):
n = create_scene("rootNode")
n.gravity.value = [1.0,2.0,3.0]
Expand Down

0 comments on commit 166f7f5

Please sign in to comment.