From d0d0e00c8a5242f5409607eb2e3e8a3e6423b6a1 Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Thu, 17 Jul 2025 11:11:40 +0200 Subject: [PATCH 1/3] Add init with kwargs for Node that allow to pass data values as input --- .../SofaPython3/Sofa/Core/Binding_Node.cpp | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp index 9644ca1d..7266be80 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp @@ -168,11 +168,36 @@ py_shared_ptr __init__noname() { return std::move(dag_node); } -py_shared_ptr __init__(const std::string& name) { +py_shared_ptr __init__no_kwargs__(const std::string& name) { auto dag_node = sofa::core::objectmodel::New(name); return std::move(dag_node); } +py_shared_ptr __init__(const std::string& name, const py::kwargs& kwargs) { + auto dag_node = sofa::core::objectmodel::New(name); + + const auto typeHandleBaseData = py::detail::get_type_handle(typeid(BaseData), false); + const auto typeHandleLinkPath = py::detail::get_type_handle(typeid(LinkPath), false); + + for (auto & kv : kwargs) + { + BaseData* d = dag_node->findData(py::cast(kv.first)); + if(d) + { + if (py::isinstance(kv.second, typeHandleBaseData)) + d->setParent(kv.second.cast()); + else if (py::isinstance(kv.second, typeHandleLinkPath)) + d->setParent(py::str(kv.second)); + else if (py::isinstance(kv.second)) + d->read(py::str(kv.second)); + else + PythonFactory::fromPython(d, py::cast(kv.second)); + } + } + + return std::move(dag_node); +} + /// Method: init (beware this is not the python __init__, this is sofa's init()) void init(Node& self) { self.init(sofa::core::execparams::defaultInstance()); } @@ -680,7 +705,8 @@ void moduleAddNode(py::module &m) { }); p.def(py::init(&__init__noname), sofapython3::doc::sofa::core::Node::init); - p.def(py::init(&__init__), sofapython3::doc::sofa::core::Node::init1Arg, py::arg("name")); + p.def(py::init(&__init__no_kwargs__), sofapython3::doc::sofa::core::Node::init1Arg, py::arg("name")); + p.def(py::init(&__init__), sofapython3::doc::sofa::core::Node::init1Arg); p.def("init", &init, sofapython3::doc::sofa::core::Node::initSofa ); p.def("add", &addKwargs, sofapython3::doc::sofa::core::Node::addKwargs); p.def("addObject", &addObjectKwargs, sofapython3::doc::sofa::core::Node::addObjectKwargs); From 5b4b1adfc222d4503000fdf85e4cd536ec8e0a70 Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Thu, 17 Jul 2025 11:17:41 +0200 Subject: [PATCH 2/3] Make a generic function out the code that set data from kwarg so tthis can be applid to all objects --- Plugin/src/SofaPython3/DataHelper.cpp | 24 +++++++++++++++++++ Plugin/src/SofaPython3/DataHelper.h | 4 ++++ .../SofaPython3/Sofa/Core/Binding_Node.cpp | 19 +-------------- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/Plugin/src/SofaPython3/DataHelper.cpp b/Plugin/src/SofaPython3/DataHelper.cpp index 6bd1f6a8..2f4ab166 100644 --- a/Plugin/src/SofaPython3/DataHelper.cpp +++ b/Plugin/src/SofaPython3/DataHelper.cpp @@ -659,4 +659,28 @@ BaseLink* addLink(py::object py_self, const std::string& name, py::object value, return link; } + +void setDataFromKwargs(Base* obj, const pybind11::kwargs& kwargs) +{ + const auto typeHandleBaseData = py::detail::get_type_handle(typeid(BaseData), false); + const auto typeHandleLinkPath = py::detail::get_type_handle(typeid(LinkPath), false); + + for (auto & kv : kwargs) + { + BaseData* d = obj->findData(py::cast(kv.first)); + if(d) + { + if (py::isinstance(kv.second, typeHandleBaseData)) + d->setParent(kv.second.cast()); + else if (py::isinstance(kv.second, typeHandleLinkPath)) + d->setParent(py::str(kv.second)); + else if (py::isinstance(kv.second)) + d->read(py::str(kv.second)); + else + PythonFactory::fromPython(d, py::cast(kv.second)); + } + } +} + + } // namespace sofapython3 diff --git a/Plugin/src/SofaPython3/DataHelper.h b/Plugin/src/SofaPython3/DataHelper.h index d689aa3b..e64e7118 100644 --- a/Plugin/src/SofaPython3/DataHelper.h +++ b/Plugin/src/SofaPython3/DataHelper.h @@ -32,6 +32,7 @@ #include #include + ////////////////////////// FORWARD DECLARATION /////////////////////////// namespace sofa { namespace defaulttype { @@ -292,6 +293,9 @@ SOFAPYTHON3_API BaseData* addData(pybind11::object py_self, const std::string& n SOFAPYTHON3_API BaseLink* addLink(pybind11::object py_self, const std::string& name, pybind11::object value, const std::string& help); SOFAPYTHON3_API bool isProtectedKeyword(const std::string& name); + +SOFAPYTHON3_API void setDataFromKwargs(Base* obj, const pybind11::kwargs& kwargs); + } // namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp index 7266be80..84bc7b32 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp @@ -176,24 +176,7 @@ py_shared_ptr __init__no_kwargs__(const std::string& name) { py_shared_ptr __init__(const std::string& name, const py::kwargs& kwargs) { auto dag_node = sofa::core::objectmodel::New(name); - const auto typeHandleBaseData = py::detail::get_type_handle(typeid(BaseData), false); - const auto typeHandleLinkPath = py::detail::get_type_handle(typeid(LinkPath), false); - - for (auto & kv : kwargs) - { - BaseData* d = dag_node->findData(py::cast(kv.first)); - if(d) - { - if (py::isinstance(kv.second, typeHandleBaseData)) - d->setParent(kv.second.cast()); - else if (py::isinstance(kv.second, typeHandleLinkPath)) - d->setParent(py::str(kv.second)); - else if (py::isinstance(kv.second)) - d->read(py::str(kv.second)); - else - PythonFactory::fromPython(d, py::cast(kv.second)); - } - } + setDataFromKwargs(dag_node.get(), kwargs); return std::move(dag_node); } From 7c2fa266586bcc97239f3fb6b16e63a4638dbf9a Mon Sep 17 00:00:00 2001 From: Paul Baksic Date: Thu, 21 Aug 2025 16:01:24 +0200 Subject: [PATCH 3/3] Add unit test for kwargs --- bindings/Sofa/tests/Simulation/Node.py | 590 +++++++++++++------------ 1 file changed, 299 insertions(+), 291 deletions(-) diff --git a/bindings/Sofa/tests/Simulation/Node.py b/bindings/Sofa/tests/Simulation/Node.py index f0cc5b35..57d5e4b1 100644 --- a/bindings/Sofa/tests/Simulation/Node.py +++ b/bindings/Sofa/tests/Simulation/Node.py @@ -6,296 +6,304 @@ import SofaRuntime class MyController(Sofa.Core.Controller): - """This is my custom controller - when init is called from Sofa this should call the python init function - This controller is used to test the method sendEvent - """ - def __init__(self, *args, **kwargs): - ## These are needed (and the normal way to override from a python class) - Sofa.Core.Controller.__init__(self, *args, **kwargs) - self.event_name = "" - self.userData = "" - self.sender = "" - - def onPythonScriptEvent(self, kwargs): - self.event_name = kwargs.get("event_name") - self.userData = kwargs.get("userData") - self.sender = kwargs.get("sender") + """This is my custom controller + when init is called from Sofa this should call the python init function + This controller is used to test the method sendEvent + """ + def __init__(self, *args, **kwargs): + ## These are needed (and the normal way to override from a python class) + Sofa.Core.Controller.__init__(self, *args, **kwargs) + self.event_name = "" + self.userData = "" + self.sender = "" + + def onPythonScriptEvent(self, kwargs): + self.event_name = kwargs.get("event_name") + self.userData = kwargs.get("userData") + self.sender = kwargs.get("sender") class Test(unittest.TestCase): - def test_SimulationConstructor(self): - root = Sofa.Core.Node("rootNode") - self.assertEqual(root.name.value, "rootNode") - - def test_Constructor(self): - root = Sofa.Core.Node("rootNode") - self.assertEqual(root.name.value, "rootNode") - - def test_GetAttr(self): - root = Sofa.Core.Node("rootNode") - root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") - c = root.addChild("child1") - self.assertTrue(c is not None) - self.assertTrue(root.child1 is not None) - - o = c.addObject("MechanicalObject", name="mechanical") - self.assertTrue(o is not None) - self.assertTrue(root.child1.mechanical is not None) - - def test_init(self): - root = Sofa.Core.Node("rootNode") - root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") - c = root.addChild("child1") - c = c.addObject("MechanicalObject", name="MO", position=[0.0,1.0,2.0]*100) - root.init() - print("TYPE: "+str(len(c.position.value))) - self.assertEqual(len(c.position.value), 100) - - def test_createObjectInvalid(self): - root = Sofa.Core.Node("rootNode") - c = root.addChild("child1") - def d(): - c.addObject([1.0,0.0,0.0]) - self.assertRaises(TypeError, d) - - def d1(): - c.addObject("NOEXISTINGCOMPONENT") - - self.assertRaises(ValueError, d1) - root.init() - - def test_addChild(self): - root = Sofa.Core.Node("rootNode") - root.addChild(Sofa.Core.Node("child1")) - self.assertTrue(hasattr(root,"child1")) - - def test_removeChild(self): - root = Sofa.Core.Node("rootNode") - c = root.addChild(Sofa.Core.Node("child1")) - c2 = root.addChild(Sofa.Core.Node("child2")) - self.assertEqual(len(root.children), 2) - self.assertTrue(hasattr(root,"child1")) - self.assertTrue(hasattr(root,"child2")) - root.removeChild(c) - self.assertEqual(len(root.children), 1) - - self.assertFalse(hasattr(root,"child1")) - root.removeChild("child2") - self.assertFalse(hasattr(root,"child2")) - self.assertEqual(len(root.children), 0) - - def test_createObjectWithParam(self): - root = Sofa.Core.Node("rootNode") - root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") - root.addObject("MechanicalObject", name="mechanical", position=[[0,0,0],[1,1,1],[2,2,2]]) - - def test_children_property(self): - root = Sofa.Core.Node("rootNode") - c1 = root.addChild(Sofa.Core.Node("child1")) - self.assertEqual(len(root.children), 1) - c2 = root.addChild(Sofa.Core.Node("child2")) - self.assertEqual(len(root.children), 2) - - self.assertEqual(root.children.at(0).name, c1.name) - self.assertEqual(root.children.at(1).name, c2.name) - root.children.remove_at(0) - self.assertEqual(len(root.children), 1) - self.assertEqual(root.children.at(0).name, c2.name) - - self.assertTrue(isinstance(root.children[0], Sofa.Core.Node)) - - def test_parents_property(self): - root = Sofa.Core.Node("rootNode") - c1 = root.addChild(Sofa.Core.Node("child1")) - c2 = root.addChild(Sofa.Core.Node("child2")) - d = c1.addChild(Sofa.Core.Node("subchild")) - d = c2.addChild(Sofa.Core.Node("subchild")) - self.assertEqual(len(d.parents), 1) - c1.addChild(d) - self.assertEqual(len(d.parents), 2) - - def test_objects_property(self): - root = Sofa.Core.Node("rootNode") - root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") - child = root.addChild(Sofa.Core.Node("child1")) - child.addObject("MechanicalObject", name="name1") - child.addObject("MechanicalObject", name="name2") - self.assertEqual(len(child.objects), 2) - child.addObject("MechanicalObject", name="name2") - self.assertEqual(len(child.objects), 3) - - def test_objects_property_contains_method(self): - root = Sofa.Core.Node("rootNode") - root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") - child = root.addChild(Sofa.Core.Node("child1")) - child.addObject("MechanicalObject", name="name1") - child.addObject("MechanicalObject", name="name2") - self.assertTrue("child1" in root.children) - self.assertFalse("child2" in root.children) - self.assertTrue("name1" in child.objects) - self.assertTrue("name2" in child.objects) - self.assertFalse("name3" in child.objects) - - def test_objects_property_remove_at_method(self): - root = Sofa.Core.Node("rootNode") - root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") - child = root.addChild(Sofa.Core.Node("child1")) - child.addObject("MechanicalObject", name="name1") - child.addObject("MechanicalObject", name="name2") - self.assertTrue("name1" in child.objects) - self.assertTrue("name2" in child.objects) - child.objects.remove_at(1) - self.assertTrue("name1" in child.objects) - self.assertFalse("name2" in child.objects) - - def test_data_property(self): - root = Sofa.Core.Node("rootNode") - self.assertTrue(hasattr(root, "__data__")) - self.assertGreater(len(root.__data__), 0) - self.assertTrue("name" in root.__data__) - self.assertFalse(hasattr(root.__data__, "invalidEntry")) - self.assertTrue(isinstance(root.__data__, Sofa.Core.DataDict)) - - def test_getItem(self): - root = Sofa.Core.Node("root") - root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") - node1 = root.addChild('node1') - object1 = root.addObject("MechanicalObject", name="object1") - node2 = node1.addChild('node2') - object2 = node2.addObject("MechanicalObject", name="object2") - - # All those are allowed syntaxes: - self.assertEqual(root[".name"], root.name) - self.assertEqual(root["name"], root.name) - - self.assertEqual(object1["name"], object1.name) - self.assertEqual(object1[".name"], object1.name) - self.assertEqual(object1["."].name, object1.name) - self.assertEqual(object1[""].name, object1.name) - - self.assertEqual(root["node1"].name, node1.name) - self.assertEqual(root["object1"], object1) - self.assertEqual(root["node1.node2"].name, node2.name) - self.assertEqual(root["name"], root.name) - self.assertEqual(root["node1.node2.object2.name"], object2.name) - - self.assertEqual(root["node1.node2.object2.name"], root.node1.node2.object2.name) - - def test_getRoot(self): - root = Sofa.Core.Node("root") - node = root.addChild("node") - self.assertEqual(node.getRoot(), root) - - def test_getRootPath(self): - root = Sofa.Core.Node("root") - node = root.addChild("node") - self.assertEqual(node.getRootPath(),"../") - - def test_getLink(self): - root = Sofa.Core.Node("root") - node = root.addChild("node") - node2 = node.addChild("node2") - self.assertEqual(node.getLinkPath(),"@/node") - self.assertEqual(node2.getLinkPath(), "@/node/node2") - - def test_hasObjectWithFastPath(self): - root = Sofa.Core.Node("root") - root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") - self.assertTrue(root.hasObject("Sofa.Component.StateContainer")) - self.assertFalse(root.hasObject("NonExistingObjectName")) - - def test_hasObjectWithDefaultPythonFunction(self): - root = Sofa.Core.Node("root") - root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") - - self.assertTrue(hasattr(root, "Sofa.Component.StateContainer")) - self.assertFalse(hasattr(root, "NonExistingObjectName")) - - def test_removeObject(self): - root = Sofa.Core.Node("root") - root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") - child = root.addChild(Sofa.Core.Node("child1")) - - obj1 = child.addObject("MechanicalObject", name="obj1") - obj2 = child.addObject("MechanicalObject", name="obj2") - self.assertEqual(len(child.objects), 2) - self.assertTrue(hasattr(child,"obj1")) - self.assertTrue(hasattr(child,"obj2")) - child.removeObject(obj1) - self.assertEqual(len(child.objects), 1) - - self.assertFalse(hasattr(child,"obj1")) - child.removeObject(obj2) - self.assertFalse(hasattr(child,"obj2")) - self.assertEqual(len(child.objects), 0) - - def test_moveChild(self): - root1 = Sofa.Core.Node("root1") - root2 = Sofa.Core.Node("root2") - child = Sofa.Core.Node("aChild") - root1.addChild(child) - self.assertEqual(len(root1.children), 1) - self.assertTrue(hasattr(root1,"aChild")) - root2.moveChild(child,root1) - self.assertEqual(len(root2.children), 1) - self.assertTrue(hasattr(root2,"aChild")) - self.assertEqual(len(root1.children), 0) - self.assertFalse(hasattr(root1,"aChild")) - - def test_isInitialized(self): - root = Sofa.Core.Node("root") - root.init() - self.assertTrue(root.isInitialized()) - - def test_getAsACreateObjectParameter(self): - root = Sofa.Core.Node("root") - node = root.addChild("node") - node2 = node.addChild("node2") - self.assertEqual(node.getAsACreateObjectParameter(),"@/node") - self.assertEqual(node2.getAsACreateObjectParameter(), "@/node/node2") - - def test_detachFromGraph(self): - root = Sofa.Core.Node("root") - node = root.addChild("node") - self.assertEqual(len(root.children),1) - node.detachFromGraph() - self.assertEqual(len(root.children),0) - - def test_getMass(self): - root = Sofa.Core.Node("root") - root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") - root.addObject("MechanicalObject") - m = root.addObject("UniformMass", name="mass", vertexMass=0.1) - self.assertEqual(m,root.getMass()) - - def test_getForceField(self): - root = Sofa.Core.Node("root") - root.addObject("RequiredPlugin", name="Sofa.Component.MechanicalLoad") - root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") - root.addObject("MechanicalObject") - ff = root.addObject('ConstantForceField', template="Vec3d", name="cff2") - self.assertEqual(ff, root.getForceField(0)) - - def test_getMechanicalState(self): - root = Sofa.Core.Node("root") - root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") - c = root.addObject("MechanicalObject") - self.assertEqual(c, root.getMechanicalState()) - - def test_getMechanicalMapping(self): - root = Sofa.Core.Node("root") - root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") - root.addObject("RequiredPlugin", name="Sofa.Component.Mapping.Linear") - root.addObject("MechanicalObject", name="t1") - root.addObject("MechanicalObject", name="t2") - mm = root.addObject("BarycentricMapping", input="@/t1", output="@/t2") - self.assertEqual(mm, root.getMechanicalMapping()) - - def test_sendEvent(self): - root = Sofa.Core.Node("rootNode") - node = root.addChild("node") - c = node.addObject(MyController(name="controller")) - root.sendEvent(root.name,"This is a test") - self.assertEqual(c.event_name, "This is a test") - self.assertEqual(c.userData, root.name) - self.assertEqual(c.sender, root) + def test_SimulationConstructor(self): + root = Sofa.Core.Node("rootNode") + self.assertEqual(root.name.value, "rootNode") + + def test_Constructor(self): + root = Sofa.Core.Node("rootNode") + self.assertEqual(root.name.value, "rootNode") + + def test_kwargs_constructor(self): + root = Sofa.Core.Node("root", gravity=[0,0,12.3], activated=False) + self.assertEqual(root.name.value, "root") + self.assertEqual(root.gravity.value[0], 0) + self.assertEqual(root.gravity.value[1], 0) + self.assertEqual(root.gravity.value[2], 12.3) + self.assertEqual(root.activated.value, False) + + def test_GetAttr(self): + root = Sofa.Core.Node("rootNode") + root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") + c = root.addChild("child1") + self.assertTrue(c is not None) + self.assertTrue(root.child1 is not None) + + o = c.addObject("MechanicalObject", name="mechanical") + self.assertTrue(o is not None) + self.assertTrue(root.child1.mechanical is not None) + + def test_init(self): + root = Sofa.Core.Node("rootNode") + root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") + c = root.addChild("child1") + c = c.addObject("MechanicalObject", name="MO", position=[0.0,1.0,2.0]*100) + root.init() + print("TYPE: "+str(len(c.position.value))) + self.assertEqual(len(c.position.value), 100) + + def test_createObjectInvalid(self): + root = Sofa.Core.Node("rootNode") + c = root.addChild("child1") + def d(): + c.addObject([1.0,0.0,0.0]) + self.assertRaises(TypeError, d) + + def d1(): + c.addObject("NOEXISTINGCOMPONENT") + + self.assertRaises(ValueError, d1) + root.init() + + def test_addChild(self): + root = Sofa.Core.Node("rootNode") + root.addChild(Sofa.Core.Node("child1")) + self.assertTrue(hasattr(root,"child1")) + + def test_removeChild(self): + root = Sofa.Core.Node("rootNode") + c = root.addChild(Sofa.Core.Node("child1")) + c2 = root.addChild(Sofa.Core.Node("child2")) + self.assertEqual(len(root.children), 2) + self.assertTrue(hasattr(root,"child1")) + self.assertTrue(hasattr(root,"child2")) + root.removeChild(c) + self.assertEqual(len(root.children), 1) + + self.assertFalse(hasattr(root,"child1")) + root.removeChild("child2") + self.assertFalse(hasattr(root,"child2")) + self.assertEqual(len(root.children), 0) + + def test_createObjectWithParam(self): + root = Sofa.Core.Node("rootNode") + root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") + root.addObject("MechanicalObject", name="mechanical", position=[[0,0,0],[1,1,1],[2,2,2]]) + + def test_children_property(self): + root = Sofa.Core.Node("rootNode") + c1 = root.addChild(Sofa.Core.Node("child1")) + self.assertEqual(len(root.children), 1) + c2 = root.addChild(Sofa.Core.Node("child2")) + self.assertEqual(len(root.children), 2) + + self.assertEqual(root.children.at(0).name, c1.name) + self.assertEqual(root.children.at(1).name, c2.name) + root.children.remove_at(0) + self.assertEqual(len(root.children), 1) + self.assertEqual(root.children.at(0).name, c2.name) + + self.assertTrue(isinstance(root.children[0], Sofa.Core.Node)) + + def test_parents_property(self): + root = Sofa.Core.Node("rootNode") + c1 = root.addChild(Sofa.Core.Node("child1")) + c2 = root.addChild(Sofa.Core.Node("child2")) + d = c1.addChild(Sofa.Core.Node("subchild")) + d = c2.addChild(Sofa.Core.Node("subchild")) + self.assertEqual(len(d.parents), 1) + c1.addChild(d) + self.assertEqual(len(d.parents), 2) + + def test_objects_property(self): + root = Sofa.Core.Node("rootNode") + root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") + child = root.addChild(Sofa.Core.Node("child1")) + child.addObject("MechanicalObject", name="name1") + child.addObject("MechanicalObject", name="name2") + self.assertEqual(len(child.objects), 2) + child.addObject("MechanicalObject", name="name2") + self.assertEqual(len(child.objects), 3) + + def test_objects_property_contains_method(self): + root = Sofa.Core.Node("rootNode") + root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") + child = root.addChild(Sofa.Core.Node("child1")) + child.addObject("MechanicalObject", name="name1") + child.addObject("MechanicalObject", name="name2") + self.assertTrue("child1" in root.children) + self.assertFalse("child2" in root.children) + self.assertTrue("name1" in child.objects) + self.assertTrue("name2" in child.objects) + self.assertFalse("name3" in child.objects) + + def test_objects_property_remove_at_method(self): + root = Sofa.Core.Node("rootNode") + root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") + child = root.addChild(Sofa.Core.Node("child1")) + child.addObject("MechanicalObject", name="name1") + child.addObject("MechanicalObject", name="name2") + self.assertTrue("name1" in child.objects) + self.assertTrue("name2" in child.objects) + child.objects.remove_at(1) + self.assertTrue("name1" in child.objects) + self.assertFalse("name2" in child.objects) + + def test_data_property(self): + root = Sofa.Core.Node("rootNode") + self.assertTrue(hasattr(root, "__data__")) + self.assertGreater(len(root.__data__), 0) + self.assertTrue("name" in root.__data__) + self.assertFalse(hasattr(root.__data__, "invalidEntry")) + self.assertTrue(isinstance(root.__data__, Sofa.Core.DataDict)) + + def test_getItem(self): + root = Sofa.Core.Node("root") + root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") + node1 = root.addChild('node1') + object1 = root.addObject("MechanicalObject", name="object1") + node2 = node1.addChild('node2') + object2 = node2.addObject("MechanicalObject", name="object2") + + # All those are allowed syntaxes: + self.assertEqual(root[".name"], root.name) + self.assertEqual(root["name"], root.name) + + self.assertEqual(object1["name"], object1.name) + self.assertEqual(object1[".name"], object1.name) + self.assertEqual(object1["."].name, object1.name) + self.assertEqual(object1[""].name, object1.name) + + self.assertEqual(root["node1"].name, node1.name) + self.assertEqual(root["object1"], object1) + self.assertEqual(root["node1.node2"].name, node2.name) + self.assertEqual(root["name"], root.name) + self.assertEqual(root["node1.node2.object2.name"], object2.name) + + self.assertEqual(root["node1.node2.object2.name"], root.node1.node2.object2.name) + + def test_getRoot(self): + root = Sofa.Core.Node("root") + node = root.addChild("node") + self.assertEqual(node.getRoot(), root) + + def test_getRootPath(self): + root = Sofa.Core.Node("root") + node = root.addChild("node") + self.assertEqual(node.getRootPath(),"../") + + def test_getLink(self): + root = Sofa.Core.Node("root") + node = root.addChild("node") + node2 = node.addChild("node2") + self.assertEqual(node.getLinkPath(),"@/node") + self.assertEqual(node2.getLinkPath(), "@/node/node2") + + def test_hasObjectWithFastPath(self): + root = Sofa.Core.Node("root") + root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") + self.assertTrue(root.hasObject("Sofa.Component.StateContainer")) + self.assertFalse(root.hasObject("NonExistingObjectName")) + + def test_hasObjectWithDefaultPythonFunction(self): + root = Sofa.Core.Node("root") + root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") + + self.assertTrue(hasattr(root, "Sofa.Component.StateContainer")) + self.assertFalse(hasattr(root, "NonExistingObjectName")) + + def test_removeObject(self): + root = Sofa.Core.Node("root") + root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") + child = root.addChild(Sofa.Core.Node("child1")) + + obj1 = child.addObject("MechanicalObject", name="obj1") + obj2 = child.addObject("MechanicalObject", name="obj2") + self.assertEqual(len(child.objects), 2) + self.assertTrue(hasattr(child,"obj1")) + self.assertTrue(hasattr(child,"obj2")) + child.removeObject(obj1) + self.assertEqual(len(child.objects), 1) + + self.assertFalse(hasattr(child,"obj1")) + child.removeObject(obj2) + self.assertFalse(hasattr(child,"obj2")) + self.assertEqual(len(child.objects), 0) + + def test_moveChild(self): + root1 = Sofa.Core.Node("root1") + root2 = Sofa.Core.Node("root2") + child = Sofa.Core.Node("aChild") + root1.addChild(child) + self.assertEqual(len(root1.children), 1) + self.assertTrue(hasattr(root1,"aChild")) + root2.moveChild(child,root1) + self.assertEqual(len(root2.children), 1) + self.assertTrue(hasattr(root2,"aChild")) + self.assertEqual(len(root1.children), 0) + self.assertFalse(hasattr(root1,"aChild")) + + def test_isInitialized(self): + root = Sofa.Core.Node("root") + root.init() + self.assertTrue(root.isInitialized()) + + def test_getAsACreateObjectParameter(self): + root = Sofa.Core.Node("root") + node = root.addChild("node") + node2 = node.addChild("node2") + self.assertEqual(node.getAsACreateObjectParameter(),"@/node") + self.assertEqual(node2.getAsACreateObjectParameter(), "@/node/node2") + + def test_detachFromGraph(self): + root = Sofa.Core.Node("root") + node = root.addChild("node") + self.assertEqual(len(root.children),1) + node.detachFromGraph() + self.assertEqual(len(root.children),0) + + def test_getMass(self): + root = Sofa.Core.Node("root") + root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") + root.addObject("MechanicalObject") + m = root.addObject("UniformMass", name="mass", vertexMass=0.1) + self.assertEqual(m,root.getMass()) + + def test_getForceField(self): + root = Sofa.Core.Node("root") + root.addObject("RequiredPlugin", name="Sofa.Component.MechanicalLoad") + root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") + root.addObject("MechanicalObject") + ff = root.addObject('ConstantForceField', template="Vec3d", name="cff2") + self.assertEqual(ff, root.getForceField(0)) + + def test_getMechanicalState(self): + root = Sofa.Core.Node("root") + root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") + c = root.addObject("MechanicalObject") + self.assertEqual(c, root.getMechanicalState()) + + def test_getMechanicalMapping(self): + root = Sofa.Core.Node("root") + root.addObject("RequiredPlugin", name="Sofa.Component.StateContainer") + root.addObject("RequiredPlugin", name="Sofa.Component.Mapping.Linear") + root.addObject("MechanicalObject", name="t1") + root.addObject("MechanicalObject", name="t2") + mm = root.addObject("BarycentricMapping", input="@/t1", output="@/t2") + self.assertEqual(mm, root.getMechanicalMapping()) + + def test_sendEvent(self): + root = Sofa.Core.Node("rootNode") + node = root.addChild("node") + c = node.addObject(MyController(name="controller")) + root.sendEvent(root.name,"This is a test") + self.assertEqual(c.event_name, "This is a test") + self.assertEqual(c.userData, root.name) + self.assertEqual(c.sender, root)