Skip to content

Commit 675191b

Browse files
Merge pull request #33 from sofa-framework/add_addLink
Add addLink method in Binding_Base to create links dynamically
2 parents 83ee817 + 98fc6de commit 675191b

File tree

6 files changed

+71
-2
lines changed

6 files changed

+71
-2
lines changed

Plugin/src/SofaPython3/DataHelper.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ along with sofaqtquick. If not, see <http://www.gnu.org/licenses/>.
3535
#include <SofaPython3/DataCache.h>
3636
#include <SofaPython3/PythonFactory.h>
3737

38+
using sofa::core::objectmodel::BaseLink;
39+
3840
namespace sofapython3
3941
{
4042

@@ -597,5 +599,30 @@ BaseData* addData(py::object py_self, const std::string& name, py::object value,
597599
return data;
598600
}
599601

602+
BaseLink* addLink(py::object py_self, const std::string& name, py::object value, const std::string& help)
603+
{
604+
Base* self = py::cast<Base*>(py_self);
605+
if (isProtectedKeyword(name))
606+
throw py::value_error("addLink: Cannot call addLink with name " + name + ": Protected keyword");
607+
608+
checkAmbiguousCreation(py_self, name, "link");
600609

610+
BaseLink::InitLink<Base> initlink(self, name, help);
611+
612+
BaseLink* link = new sofa::core::objectmodel::SingleLink<Base, Base, BaseLink::FLAG_MULTILINK>(initlink);
613+
if (py::isinstance<std::string>(value))
614+
{
615+
auto linkpath = py::cast<std::string>(value);
616+
if (linkpath[0] != '@')
617+
linkpath = "@" + linkpath;
618+
if (!link->read(linkpath))
619+
throw py::value_error("addLink: Cannot read link path " + linkpath + ": is link valid?");
620+
}
621+
else if (py::isinstance<Base*>(value))
622+
link->setLinkedBase(py::cast<Base*>(value));
623+
624+
// self->addLink(link);
625+
return link;
601626
}
627+
628+
} // namespace sofapython3

Plugin/src/SofaPython3/DataHelper.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ namespace py { using namespace pybind11; }
5959

6060
using sofa::core::objectmodel::Base;
6161
using sofa::core::objectmodel::BaseData;
62+
using sofa::core::objectmodel::BaseLink;
6263
using sofa::core::objectmodel::BaseNode;
6364
using sofa::core::objectmodel::BaseObject;
6465
using sofa::defaulttype::AbstractTypeInfo;
@@ -189,6 +190,7 @@ class scoped_writeonly_access
189190
};
190191

191192
SOFAPYTHON3_API BaseData* addData(py::object py_self, const std::string& name, py::object value = py::object(), py::object defaultValue = py::object(), const std::string& help = "", const std::string& group = "Property", std::string type = "");
193+
SOFAPYTHON3_API BaseLink* addLink(py::object py_self, const std::string& name, py::object value, const std::string& help);
192194
SOFAPYTHON3_API bool isProtectedKeyword(const std::string& name);
193195

194196
} // namespace sofapython3

bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ py::object BindingBase::GetAttr(Base* self, const std::string& s, bool doThrowEx
9393
/// Search if there is a link with the given name.
9494
/// If this is the case returns the corresponding python type.
9595
if(BaseLink* l = self->findLink(s))
96-
return py::cast(l->getLinkedBase());
96+
return py::cast(l);
9797

9898
/// Search if we are quering for a 'magic' and private __data__ property
9999
/// this one allows to traverse all the data in the object
@@ -310,6 +310,11 @@ BaseData* BindingBase::addData(py::object py_self, const std::string& name, py::
310310
return sofapython3::addData(py_self, name, value, defaultValue, help, group, type);
311311
}
312312

313+
BaseLink* BindingBase::addLink(py::object py_self, const std::string& name, py::object value, const std::string& help)
314+
{
315+
return sofapython3::addLink(py_self, name, value, help);
316+
}
317+
313318
BaseData* BindingBase::addDataFromData(Base* self, py::object d)
314319
{
315320
BaseData* data = py::cast<BaseData*>(d);
@@ -394,6 +399,12 @@ py::object BindingBase::getData(Base& self, const std::string& s)
394399
return py::none();
395400
}
396401

402+
403+
std::string BindingBase::getPathName(Base& self)
404+
{
405+
return self.toBaseNode() ? self.toBaseNode()->getPathName() : self.toBaseObject()->getPathName();
406+
}
407+
397408
py::object BindingBase::setDataValues(Base& self, py::kwargs kwargs)
398409
{
399410
for(auto key : kwargs)
@@ -432,6 +443,7 @@ void moduleAddBase(py::module &m)
432443
base.def("getLinks", &BindingBase::getLinks, pybind11::return_value_policy::reference, sofapython3::doc::base::getLinks);
433444
base.def("addData", &BindingBase::addData, "name"_a, "value"_a = py::none(), "default"_a = py::none(), "help"_a = "", "group"_a = "", "type"_a = "", sofapython3::doc::base::addData);
434445
base.def("addData", &BindingBase::addDataFromData, sofapython3::doc::base::addDataInitialized);
446+
base.def("addLink", &BindingBase::addLink, "name"_a, "value"_a = py::none(), "help"_a = "", sofapython3::doc::base::addLink);
435447
base.def("__getattr__", &BindingBase::__getattr__);
436448
base.def("__setattr__", &BindingBase::__setattr__);
437449
base.def("getData", &BindingBase::getData, sofapython3::doc::base::getData);
@@ -440,6 +452,7 @@ void moduleAddBase(py::module &m)
440452
base.def("getLoggedMessagesAsString", &BindingBase::getLoggedMessagesAsString, sofapython3::doc::base::getLoggedMessagesAsString);
441453
base.def("countLoggedMessages", &BindingBase::countLoggedMessages, sofapython3::doc::base::countLoggedMessages);
442454
base.def("clearLoggedMessages", &BindingBase::clearLoggedMessages, sofapython3::doc::base::clearLoggedMessages);
455+
base.def("getPathName", &BindingBase::getPathName);
443456
base.def("setDataValues", &BindingBase::setDataValues, sofapython3::doc::base::setDataValues);
444457
}
445458

bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ namespace py {
5151
using namespace pybind11::literals;
5252
using sofa::core::objectmodel::Base;
5353
using sofa::core::objectmodel::BaseData;
54+
using sofa::core::objectmodel::BaseLink;
5455
using sofa::core::sptr;
5556

5657
class BindingBase
@@ -71,6 +72,7 @@ class BindingBase
7172
static py::list getLinks(Base& self);
7273
static BaseData* addData(py::object py_self, const std::string& name, py::object value = py::object(), py::object defaultValue = py::object(), const std::string& help = "", const std::string& group = "Property", std::string type = "");
7374
static BaseData* addDataFromData(Base* self, py::object d);
75+
static BaseLink* addLink(py::object py_self, const std::string& name, py::object value, const std::string& help);
7476
static py::list __dir__(Base* self);
7577
static py::object __getattr__(py::object self, const std::string& s);
7678
static void __setattr__(py::object self, const std::string& s, py::object value);
@@ -79,6 +81,7 @@ class BindingBase
7981
static py::object getLoggedMessagesAsString(Base& self);
8082
static py::object countLoggedMessages(Base& self);
8183
static py::object clearLoggedMessages(Base& self);
84+
static std::string getPathName(Base& self);
8285
};
8386

8487

bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ py::object getOwnerBase(BaseLink& self)
6565
return PythonFactory::toPython(self.getOwnerBase());
6666
}
6767

68+
std::string getPathName(BaseLink& self)
69+
{
70+
auto n = self.getOwnerBase()->toBaseNode();
71+
auto o = self.getOwnerBase()->toBaseObject();
72+
return (n ? n->getPathName() : o->getPathName()) + "." + self.getName();
73+
}
74+
6875
void moduleAddBaseLink(py::module& m)
6976
{
7077
py::class_<BaseLink, std::unique_ptr<sofa::core::objectmodel::BaseLink, pybind11::nodelete>> link(m, "Link", sofapython3::doc::baseLink::baseLinkClass);
@@ -87,8 +94,11 @@ void moduleAddBaseLink(py::module& m)
8794

8895
link.def("getLinkedData", &BaseLink::getLinkedData, sofapython3::doc::baseLink::getLinkedData);
8996
link.def("getLinkedBase", getLinkedBase, "index"_a = 0, sofapython3::doc::baseLink::getLinkedBase);
97+
link.def("setLinkedBase", &BaseLink::setLinkedBase, sofapython3::doc::baseLink::getLinkedBase);
98+
9099

91100
link.def("getLinkedPath", &BaseLink::getLinkedPath, "index"_a = 0, sofapython3::doc::baseLink::getLinkedPath);
101+
link.def("getPathName", getPathName, sofapython3::doc::baseLink::getLinkedPath);
92102
link.def("read", &BaseLink::read, sofapython3::doc::baseLink::read);
93103

94104
}

bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base_doc.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,24 @@ static auto addData =
127127
:type name: string
128128
:type value: object
129129
:type help: string
130-
:type groupe: string
130+
:type group: string
131131
:type type: string
132132
)";
133133

134+
static auto addLink =
135+
R"(
136+
Create a Link to a SOFA component and adds it to the base.
137+
Note that this method should only be called if the field was not initialized with the initLink method
138+
:param self: the base itself
139+
:param name: the name of the link to be added
140+
:param value: the value from which the data can be created (either a pathname or a SofaBase)
141+
:param help: help message that describes the link to be created
142+
:type self: object
143+
:type name: string
144+
:type value: object
145+
:type help: string
146+
)";
147+
134148
static auto addDataInitialized =
135149
R"(
136150
Add a data field.

0 commit comments

Comments
 (0)