From 9222203286d24117035c6074197a4b30d4217fa6 Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Mon, 23 Sep 2024 11:53:11 +0200 Subject: [PATCH 01/20] Fix name in ClassEntry Binding_ObjectFactory.cpp The name was missing. Signed-off-by: Damien Marchal <damien.marchal@univ-lille1.fr> --- .../src/SofaPython3/Sofa/Core/Binding_ObjectFactory.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ObjectFactory.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ObjectFactory.cpp index 2be5a357..71dbfe45 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ObjectFactory.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ObjectFactory.cpp @@ -169,9 +169,11 @@ py::dict dataAlias(const ObjectFactory::ClassEntry &self) void moduleAddObjectFactory(py::module &m) { - py::class_<ObjectFactory> factory (m, "ObjectFactory", sofapython3::doc::objectmodel::ObjectFactoryClass); + py::class_<ObjectFactory> factory (m, "ObjectFactory", + sofapython3::doc::objectmodel::ObjectFactoryClass); - py::class_<ObjectFactory::ClassEntry> entry(m, sofapython3::doc::objectmodel::ClassEntryClass); + py::class_<ObjectFactory::ClassEntry> entry(m, "ClassEntry", + sofapython3::doc::objectmodel::ClassEntryClass); entry.def_property_readonly("className", &className); entry.def_property_readonly("aliases", &aliases); entry.def_property_readonly("description", &description); From d4648bd3185c6c1e4a1dff152ab94982c2fd2565 Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Mon, 23 Sep 2024 11:54:37 +0200 Subject: [PATCH 02/20] Add experimental docstring for stub generation --- .../SofaPython3/Sofa/Core/Binding_Node.cpp | 20 +++++++++++-- .../SofaPython3/Sofa/Core/Binding_Node_doc.h | 30 +++++++++++++++++++ 2 files changed, 48 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 dda992d1..9c282941 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp @@ -294,6 +294,14 @@ py::object addObjectKwargs(Node* self, const std::string& type, const py::kwargs return PythonFactory::toPython(object.get()); } +/// Implement the addObject function. +py::object addObject2(Node* self, const py::type type, const py::kwargs& kwargs) +{ + auto name = py::cast<std::string>(type.attr("__name__")); + std::cout << "PATH TO CREATE AN OBJECT OF T>YPE 2 " << name << std::endl; + return addObjectKwargs(self, name, kwargs); +} + /// Implement the addObject function. py::object addKwargs(Node* self, const py::object& callable, const py::kwargs& kwargs) { @@ -629,8 +637,16 @@ void moduleAddNode(py::module &m) { p.def(py::init(&__init__), sofapython3::doc::sofa::core::Node::init1Arg, py::arg("name")); 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); - p.def("addObject", &addObject, sofapython3::doc::sofa::core::Node::addObject, py::keep_alive<0, 2>()); + + { + py::options options; + options.disable_function_signatures(); + + p.def("addObject", &addObject2, sofapython3::doc::sofa::core::Node::addObject2); + p.def("addObject", &addObjectKwargs, sofapython3::doc::sofa::core::Node::addObjectKwargs); + p.def("addObject", &addObject, sofapython3::doc::sofa::core::Node::addObject, py::keep_alive<0, 2>()); + } + p.def("createObject", &createObject, sofapython3::doc::sofa::core::Node::createObject, py::keep_alive<0, 2>()); p.def("hasObject", &hasObject, sofapython3::doc::sofa::core::Node::hasObject); p.def("getObject", &getObject, sofapython3::doc::sofa::core::Node::getObject); diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node_doc.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node_doc.h index 3f971926..36c48f7f 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node_doc.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node_doc.h @@ -124,6 +124,36 @@ static auto addKwargs = )"; +static auto addObject2 = + R"(addObject(*args, **kwargs) +Overloaded function. + +1. addObject(self: Sofa.Core.Node, arg0: str, **kwargs) -> Sofa.Core.Object + + +Add an object a real type + + +2. addObject(self, arg0: type[T], **kwargs) -> T + + +The dirty trick + + +3. addObject(self, arg0: type[T], dict) -> T + + +The dirty trick to get parameters input. + + +4. addObject[T](self, component_type: T, parameters: dict) -> T + + +The 3.12 version of types... + + +)"; + static auto addObjectKwargs = R"( Add an object. From 0e11a6c72d3128826acd1770e9f45219cf597193 Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Mon, 23 Sep 2024 12:24:18 +0200 Subject: [PATCH 03/20] Remove Sofa.Components. I suspect this code to have been integrated in the SofaPython3 by mistake and to have never worked. By looking at it it may be an experiment to allow syntax like this import Sofa.Components Sofa.Components.MechanicalObject() ... --- bindings/Sofa/CMakeLists.txt | 1 - bindings/Sofa/package/__init__.py | 1 - .../Sofa/Components/CMakeLists.txt | 21 --- .../Sofa/Components/Submodule_Components.cpp | 142 ------------------ .../Sofa/Components/Submodule_Components.h | 30 ---- 5 files changed, 195 deletions(-) delete mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Components/CMakeLists.txt delete mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Components/Submodule_Components.cpp delete mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Components/Submodule_Components.h diff --git a/bindings/Sofa/CMakeLists.txt b/bindings/Sofa/CMakeLists.txt index 9bfab5b5..63227a2b 100644 --- a/bindings/Sofa/CMakeLists.txt +++ b/bindings/Sofa/CMakeLists.txt @@ -1,7 +1,6 @@ project(Bindings.Sofa) set(SOFABINDINGS_MODULE_LIST - Components Core Helper Simulation diff --git a/bindings/Sofa/package/__init__.py b/bindings/Sofa/package/__init__.py index 5d77db2c..8b4a62b2 100644 --- a/bindings/Sofa/package/__init__.py +++ b/bindings/Sofa/package/__init__.py @@ -161,7 +161,6 @@ import Sofa.Core import Sofa.Simulation import Sofa.Types -import Sofa.Components import SofaTypes from .prefab import * diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Components/CMakeLists.txt b/bindings/Sofa/src/SofaPython3/Sofa/Components/CMakeLists.txt deleted file mode 100644 index 67c1e21b..00000000 --- a/bindings/Sofa/src/SofaPython3/Sofa/Components/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -project(Bindings.Sofa.Components) - -set(HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_Components.h -) - -set(SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_Components.cpp -) - -sofa_find_package(Sofa.Simulation.Core REQUIRED) - -SP3_add_python_module( - TARGET ${PROJECT_NAME} - PACKAGE Bindings.Sofa - MODULE Components - DESTINATION Sofa - SOURCES ${SOURCE_FILES} - HEADERS ${HEADER_FILES} - DEPENDS Sofa.Simulation.Core SofaPython3::Plugin -) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Components/Submodule_Components.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Components/Submodule_Components.cpp deleted file mode 100644 index 639ea6d2..00000000 --- a/bindings/Sofa/src/SofaPython3/Sofa/Components/Submodule_Components.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2021 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see <http://www.gnu.org/licenses/>. * -******************************************************************************* -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - - -#include <iostream> - -#include <sofa/core/ObjectFactory.h> -using sofa::core::objectmodel::BaseObjectDescription; -using sofa::core::ObjectFactory; - -#include <sofa/helper/logging/Messaging.h> -using sofa::helper::logging::Message; - -#include <sofa/simulation/Node.h> -using sofa::simulation::Node; - -#include <SofaPython3/DataHelper.h> -#include <SofaPython3/Sofa/Core/Binding_Base.h> -#include <SofaPython3/Sofa/Core/Binding_BaseObject.h> - -#include <sofa/core/init.h> -#include <sofa/helper/init.h> -#include <sofa/simulation/init.h> - -namespace py = pybind11; -using namespace py::literals; - -namespace sofapython3 -{ - -class FCreator -{ -public: - FCreator(const std::string& n) - { - name = n; - } - std::string name; -}; - -PYBIND11_MODULE(Components, m) -{ - // These are needed to force the dynamic loading of module dependencies (found in CMakeLists.txt) - sofa::core::init(); - sofa::helper::init(); - sofa::simulation::core::init(); - - py::class_<FCreator> mm(m, "Creator"); - mm.def("__call__", [](FCreator& s, const py::args& args, const py::kwargs& kwargs){ - if(args.size() != 1) - { - throw py::type_error("Invalid number of arguments. Only 1 argument of type 'Node' is allowed."); - } - - py::object pynode = args[0]; - if(!py::isinstance<sofa::simulation::Node>(pynode)) - { - throw py::type_error(std::string("Invalid first argument. Expecting 'Node' but got ") + py::cast<std::string>(py::str(pynode))); - } - - auto node = py::cast<py_shared_ptr<sofa::simulation::Node>>(pynode); - - /// Prepare the description to hold the different python attributes as data field's - /// arguments then create the object. - BaseObjectDescription desc {s.name.c_str(), s.name.c_str()}; - fillBaseObjectdescription(desc, kwargs); - auto object = py_shared_ptr<sofa::core::objectmodel::BaseObject>(ObjectFactory::getInstance()->createObject(node.get(), &desc)); - - /// After calling createObject the returned value can be either a nullptr - /// or non-null but with error message or non-null. - /// Let's first handle the case when the returned pointer is null. - if(!object) - { - std::stringstream tmp ; - for(auto& s : desc.getErrors()) - tmp << s << msgendl ; - throw py::value_error(tmp.str()); - } - - //checkParamUsage(object.get(), desc); - - /// Convert the logged messages in the object's internal logging into python exception. - /// this is not a very fast way to do that...but well...python is slow anyway. And serious - /// error management has a very high priority. If performance becomes an issue we will fix it - /// when needed. - if(object->countLoggedMessages({Message::Error})) - { - throw py::value_error(object->getLoggedMessagesAsString({Message::Error})); - } - - return py::cast(object); - }); - - m.def("__getattr__", [](const std::string& name) -> py::object - { - return py::cast(new FCreator(name)); - }); - - // THIS PART IS NOT WORKING... - //todo(dmarchal 04/07/2019): do it or delete it in one year. -// py::list names; -// std::vector<ObjectFactory::ClassEntry::SPtr> entries ; -// ObjectFactory::getInstance()->getAllEntries(entries) ; - -// for(auto& entry : entries) -// { -// names.append(entry->className); -// } - -// simulation.def("__dir__", []() -> py::object -// { -// py::list names; -// std::vector<ObjectFactory::ClassEntry::SPtr> entries ; -// ObjectFactory::getInstance()->getAllEntries(entries) ; - -// for(auto& entry : entries) -// { -// names.append(entry->className); -// } -// return names; //std::move(names); -// }); - -} - -} /// namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Components/Submodule_Components.h b/bindings/Sofa/src/SofaPython3/Sofa/Components/Submodule_Components.h deleted file mode 100644 index 8c22387f..00000000 --- a/bindings/Sofa/src/SofaPython3/Sofa/Components/Submodule_Components.h +++ /dev/null @@ -1,30 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2021 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see <http://www.gnu.org/licenses/>. * -******************************************************************************* -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#pragma once - -#include <pybind11/pybind11.h> - -namespace sofapython3 -{ -namespace py { using namespace pybind11; } - -} ///namespace sofapython3 - From ddead4d85aaba2b642ce7530511827722d77bbf8 Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Mon, 23 Sep 2024 14:58:13 +0200 Subject: [PATCH 04/20] Example on how to fix pybind11 type forward declaration so stubgens knows about them. The problem: Depending on the definition order of the binded classes, there may have incorrect types if Base is useing BaseData... but BaseData is only binded after Base. The PR propose a solution for that using a decidcated "forward" registration patter. --- .../src/SofaPython3/Sofa/Core/Binding_Base.cpp | 5 +++++ .../SofaPython3/Sofa/Core/Binding_BaseData.cpp | 16 +++++++++++++++- .../src/SofaPython3/Sofa/Core/Binding_BaseData.h | 1 + .../SofaPython3/Sofa/Core/Binding_BaseLink.cpp | 14 +++++++++++++- .../src/SofaPython3/Sofa/Core/Binding_BaseLink.h | 1 + .../Sofa/Core/Binding_ObjectFactory.cpp | 6 ++++-- 6 files changed, 39 insertions(+), 4 deletions(-) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp index 88f3a6df..6aa8d763 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp @@ -34,6 +34,8 @@ using sofa::helper::WriteOnlyAccessor; #include <SofaPython3/PythonFactory.h> +#include <SofaPython3/Sofa/Core/Binding_BaseData.h> +#include <SofaPython3/Sofa/Core/Binding_BaseLink.h> #include <SofaPython3/Sofa/Core/Binding_LinkPath.h> #include <SofaPython3/Sofa/Core/Binding_Base.h> #include <SofaPython3/Sofa/Core/Binding_Base_doc.h> @@ -449,6 +451,9 @@ py::object BindingBase::setDataValues(Base& self, py::kwargs kwargs) void moduleAddBase(py::module &m) { + moduleForwardAddBaseData(m); + moduleForwardAddBaseLink(m); + py::class_<Base, py_shared_ptr<Base>> base(m, "Base", py::dynamic_attr(), doc::base::BaseClass); /// set & get the name as string. The alternative is to access the data field using /// obj.name.value = "aName" diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp index f70de7c9..ecc83750 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp @@ -192,10 +192,24 @@ std::string getValueTypeString(BaseData* data) return data->getValueTypeInfo()->name(); } +auto getPythonClassForBaseData(py::module& m) +{ + /// Register the BaseData binding into the pybind11 system. + static py::class_<BaseData, std::unique_ptr<sofa::core::objectmodel::BaseData, pybind11::nodelete>> data(m, "Data", sofapython3::doc::baseData::BaseDataClass); + return data; +} + +void moduleForwardAddBaseData(py::module& m) +{ + getPythonClassForBaseData(m); +} + void moduleAddBaseData(py::module& m) { /// Register the BaseData binding into the pybind11 system. - py::class_<BaseData, std::unique_ptr<sofa::core::objectmodel::BaseData, pybind11::nodelete>> data(m, "Data", sofapython3::doc::baseData::BaseDataClass); + //py::class_<BaseData, std::unique_ptr<sofa::core::objectmodel::BaseData, pybind11::nodelete>> data(m, "Data", sofapython3::doc::baseData::BaseDataClass); + + auto data =getPythonClassForBaseData(m); data.def("getName", [](BaseData& b){ return b.getName(); }, sofapython3::doc::baseData::getName); data.def("setName", [](BaseData& b, const std::string& s){ b.setName(s); }, sofapython3::doc::baseData::setName); data.def("getCounter", [](BaseData& self) { return self.getCounter(); }, sofapython3::doc::baseData::getCounter); diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h index 6a747d1d..badd6522 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h @@ -24,6 +24,7 @@ namespace sofapython3 { + void moduleForwardAddBaseData(pybind11::module& m); void moduleAddBaseData(pybind11::module& m); } /// sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.cpp index 101b88f8..c658eaec 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.cpp @@ -91,9 +91,21 @@ void __setattr__(py::object self, const std::string& s, py::object value) } } +auto getPythonClassForBaseLink(py::module& m) +{ + /// Register the BaseData binding into the pybind11 system. + static py::class_<BaseLink> link(m, "Link", sofapython3::doc::baseLink::baseLinkClass); + return link; +} + +void moduleForwardAddBaseLink(py::module& m) +{ + getPythonClassForBaseLink(m); +} + void moduleAddBaseLink(py::module& m) { - py::class_<BaseLink> link(m, "Link", sofapython3::doc::baseLink::baseLinkClass); + auto link = getPythonClassForBaseLink(m); link.def("getName", &BaseLink::getName, sofapython3::doc::baseLink::getName); link.def("setName", &BaseLink::setName, sofapython3::doc::baseLink::setName); link.def("isMultiLink", &BaseLink::isMultiLink, sofapython3::doc::baseLink::isMultiLink); diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h index 6f03d5af..1cf5df4a 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h @@ -24,6 +24,7 @@ namespace sofapython3 { + void moduleForwardAddBaseLink(pybind11::module& m); void moduleAddBaseLink(pybind11::module& m); } /// sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ObjectFactory.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ObjectFactory.cpp index 2be5a357..71dbfe45 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ObjectFactory.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ObjectFactory.cpp @@ -169,9 +169,11 @@ py::dict dataAlias(const ObjectFactory::ClassEntry &self) void moduleAddObjectFactory(py::module &m) { - py::class_<ObjectFactory> factory (m, "ObjectFactory", sofapython3::doc::objectmodel::ObjectFactoryClass); + py::class_<ObjectFactory> factory (m, "ObjectFactory", + sofapython3::doc::objectmodel::ObjectFactoryClass); - py::class_<ObjectFactory::ClassEntry> entry(m, sofapython3::doc::objectmodel::ClassEntryClass); + py::class_<ObjectFactory::ClassEntry> entry(m, "ClassEntry", + sofapython3::doc::objectmodel::ClassEntryClass); entry.def_property_readonly("className", &className); entry.def_property_readonly("aliases", &aliases); entry.def_property_readonly("description", &description); From fca789f7165533fccbf1bc0939aa6413f7802178 Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Mon, 23 Sep 2024 14:58:13 +0200 Subject: [PATCH 05/20] Example on how to fix pybind11 type forward declaration so stubgens knows about them. The problem: Depending on the definition order of the binded classes, there may have incorrect types if Base is useing BaseData... but BaseData is only binded after Base. The PR propose a solution for that using a decidcated "forward" registration patter. --- .../src/SofaPython3/Sofa/Core/Binding_Base.cpp | 5 +++++ .../SofaPython3/Sofa/Core/Binding_BaseData.cpp | 16 +++++++++++++++- .../src/SofaPython3/Sofa/Core/Binding_BaseData.h | 1 + .../SofaPython3/Sofa/Core/Binding_BaseLink.cpp | 14 +++++++++++++- .../src/SofaPython3/Sofa/Core/Binding_BaseLink.h | 1 + .../Sofa/Core/Binding_ObjectFactory.cpp | 6 ++++-- 6 files changed, 39 insertions(+), 4 deletions(-) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp index 88f3a6df..6aa8d763 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp @@ -34,6 +34,8 @@ using sofa::helper::WriteOnlyAccessor; #include <SofaPython3/PythonFactory.h> +#include <SofaPython3/Sofa/Core/Binding_BaseData.h> +#include <SofaPython3/Sofa/Core/Binding_BaseLink.h> #include <SofaPython3/Sofa/Core/Binding_LinkPath.h> #include <SofaPython3/Sofa/Core/Binding_Base.h> #include <SofaPython3/Sofa/Core/Binding_Base_doc.h> @@ -449,6 +451,9 @@ py::object BindingBase::setDataValues(Base& self, py::kwargs kwargs) void moduleAddBase(py::module &m) { + moduleForwardAddBaseData(m); + moduleForwardAddBaseLink(m); + py::class_<Base, py_shared_ptr<Base>> base(m, "Base", py::dynamic_attr(), doc::base::BaseClass); /// set & get the name as string. The alternative is to access the data field using /// obj.name.value = "aName" diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp index f70de7c9..ecc83750 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp @@ -192,10 +192,24 @@ std::string getValueTypeString(BaseData* data) return data->getValueTypeInfo()->name(); } +auto getPythonClassForBaseData(py::module& m) +{ + /// Register the BaseData binding into the pybind11 system. + static py::class_<BaseData, std::unique_ptr<sofa::core::objectmodel::BaseData, pybind11::nodelete>> data(m, "Data", sofapython3::doc::baseData::BaseDataClass); + return data; +} + +void moduleForwardAddBaseData(py::module& m) +{ + getPythonClassForBaseData(m); +} + void moduleAddBaseData(py::module& m) { /// Register the BaseData binding into the pybind11 system. - py::class_<BaseData, std::unique_ptr<sofa::core::objectmodel::BaseData, pybind11::nodelete>> data(m, "Data", sofapython3::doc::baseData::BaseDataClass); + //py::class_<BaseData, std::unique_ptr<sofa::core::objectmodel::BaseData, pybind11::nodelete>> data(m, "Data", sofapython3::doc::baseData::BaseDataClass); + + auto data =getPythonClassForBaseData(m); data.def("getName", [](BaseData& b){ return b.getName(); }, sofapython3::doc::baseData::getName); data.def("setName", [](BaseData& b, const std::string& s){ b.setName(s); }, sofapython3::doc::baseData::setName); data.def("getCounter", [](BaseData& self) { return self.getCounter(); }, sofapython3::doc::baseData::getCounter); diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h index 6a747d1d..badd6522 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h @@ -24,6 +24,7 @@ namespace sofapython3 { + void moduleForwardAddBaseData(pybind11::module& m); void moduleAddBaseData(pybind11::module& m); } /// sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.cpp index 101b88f8..c658eaec 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.cpp @@ -91,9 +91,21 @@ void __setattr__(py::object self, const std::string& s, py::object value) } } +auto getPythonClassForBaseLink(py::module& m) +{ + /// Register the BaseData binding into the pybind11 system. + static py::class_<BaseLink> link(m, "Link", sofapython3::doc::baseLink::baseLinkClass); + return link; +} + +void moduleForwardAddBaseLink(py::module& m) +{ + getPythonClassForBaseLink(m); +} + void moduleAddBaseLink(py::module& m) { - py::class_<BaseLink> link(m, "Link", sofapython3::doc::baseLink::baseLinkClass); + auto link = getPythonClassForBaseLink(m); link.def("getName", &BaseLink::getName, sofapython3::doc::baseLink::getName); link.def("setName", &BaseLink::setName, sofapython3::doc::baseLink::setName); link.def("isMultiLink", &BaseLink::isMultiLink, sofapython3::doc::baseLink::isMultiLink); diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h index 6f03d5af..1cf5df4a 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h @@ -24,6 +24,7 @@ namespace sofapython3 { + void moduleForwardAddBaseLink(pybind11::module& m); void moduleAddBaseLink(pybind11::module& m); } /// sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ObjectFactory.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ObjectFactory.cpp index 2be5a357..71dbfe45 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ObjectFactory.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_ObjectFactory.cpp @@ -169,9 +169,11 @@ py::dict dataAlias(const ObjectFactory::ClassEntry &self) void moduleAddObjectFactory(py::module &m) { - py::class_<ObjectFactory> factory (m, "ObjectFactory", sofapython3::doc::objectmodel::ObjectFactoryClass); + py::class_<ObjectFactory> factory (m, "ObjectFactory", + sofapython3::doc::objectmodel::ObjectFactoryClass); - py::class_<ObjectFactory::ClassEntry> entry(m, sofapython3::doc::objectmodel::ClassEntryClass); + py::class_<ObjectFactory::ClassEntry> entry(m, "ClassEntry", + sofapython3::doc::objectmodel::ClassEntryClass); entry.def_property_readonly("className", &className); entry.def_property_readonly("aliases", &aliases); entry.def_property_readonly("description", &description); From a9a61d9b808fb4da842fdd0699f9c9390664b7b7 Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Mon, 23 Sep 2024 14:58:13 +0200 Subject: [PATCH 06/20] Example on how to fix pybind11 type forward declaration so stubgens knows about them. The problem: Depending on the definition order of the binded classes, there may have incorrect types if Base is useing BaseData... but BaseData is only binded after Base. The PR propose a solution for that using a decidcated "forward" registration patter. --- .../src/SofaPython3/Sofa/Core/Binding_Base.cpp | 5 +++++ .../SofaPython3/Sofa/Core/Binding_BaseData.cpp | 16 +++++++++++++++- .../src/SofaPython3/Sofa/Core/Binding_BaseData.h | 1 + .../SofaPython3/Sofa/Core/Binding_BaseLink.cpp | 14 +++++++++++++- .../src/SofaPython3/Sofa/Core/Binding_BaseLink.h | 1 + 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp index 88f3a6df..6aa8d763 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp @@ -34,6 +34,8 @@ using sofa::helper::WriteOnlyAccessor; #include <SofaPython3/PythonFactory.h> +#include <SofaPython3/Sofa/Core/Binding_BaseData.h> +#include <SofaPython3/Sofa/Core/Binding_BaseLink.h> #include <SofaPython3/Sofa/Core/Binding_LinkPath.h> #include <SofaPython3/Sofa/Core/Binding_Base.h> #include <SofaPython3/Sofa/Core/Binding_Base_doc.h> @@ -449,6 +451,9 @@ py::object BindingBase::setDataValues(Base& self, py::kwargs kwargs) void moduleAddBase(py::module &m) { + moduleForwardAddBaseData(m); + moduleForwardAddBaseLink(m); + py::class_<Base, py_shared_ptr<Base>> base(m, "Base", py::dynamic_attr(), doc::base::BaseClass); /// set & get the name as string. The alternative is to access the data field using /// obj.name.value = "aName" diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp index f70de7c9..ecc83750 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp @@ -192,10 +192,24 @@ std::string getValueTypeString(BaseData* data) return data->getValueTypeInfo()->name(); } +auto getPythonClassForBaseData(py::module& m) +{ + /// Register the BaseData binding into the pybind11 system. + static py::class_<BaseData, std::unique_ptr<sofa::core::objectmodel::BaseData, pybind11::nodelete>> data(m, "Data", sofapython3::doc::baseData::BaseDataClass); + return data; +} + +void moduleForwardAddBaseData(py::module& m) +{ + getPythonClassForBaseData(m); +} + void moduleAddBaseData(py::module& m) { /// Register the BaseData binding into the pybind11 system. - py::class_<BaseData, std::unique_ptr<sofa::core::objectmodel::BaseData, pybind11::nodelete>> data(m, "Data", sofapython3::doc::baseData::BaseDataClass); + //py::class_<BaseData, std::unique_ptr<sofa::core::objectmodel::BaseData, pybind11::nodelete>> data(m, "Data", sofapython3::doc::baseData::BaseDataClass); + + auto data =getPythonClassForBaseData(m); data.def("getName", [](BaseData& b){ return b.getName(); }, sofapython3::doc::baseData::getName); data.def("setName", [](BaseData& b, const std::string& s){ b.setName(s); }, sofapython3::doc::baseData::setName); data.def("getCounter", [](BaseData& self) { return self.getCounter(); }, sofapython3::doc::baseData::getCounter); diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h index 6a747d1d..badd6522 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h @@ -24,6 +24,7 @@ namespace sofapython3 { + void moduleForwardAddBaseData(pybind11::module& m); void moduleAddBaseData(pybind11::module& m); } /// sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.cpp index 101b88f8..c658eaec 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.cpp @@ -91,9 +91,21 @@ void __setattr__(py::object self, const std::string& s, py::object value) } } +auto getPythonClassForBaseLink(py::module& m) +{ + /// Register the BaseData binding into the pybind11 system. + static py::class_<BaseLink> link(m, "Link", sofapython3::doc::baseLink::baseLinkClass); + return link; +} + +void moduleForwardAddBaseLink(py::module& m) +{ + getPythonClassForBaseLink(m); +} + void moduleAddBaseLink(py::module& m) { - py::class_<BaseLink> link(m, "Link", sofapython3::doc::baseLink::baseLinkClass); + auto link = getPythonClassForBaseLink(m); link.def("getName", &BaseLink::getName, sofapython3::doc::baseLink::getName); link.def("setName", &BaseLink::setName, sofapython3::doc::baseLink::setName); link.def("isMultiLink", &BaseLink::isMultiLink, sofapython3::doc::baseLink::isMultiLink); diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h index 6f03d5af..1cf5df4a 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h @@ -24,6 +24,7 @@ namespace sofapython3 { + void moduleForwardAddBaseLink(pybind11::module& m); void moduleAddBaseLink(pybind11::module& m); } /// sofapython3 From 7fd98e6d8188cbd901bfb804c7c642318d768493 Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Mon, 23 Sep 2024 12:24:18 +0200 Subject: [PATCH 07/20] Remove Sofa.Components. I suspect this code to have been integrated in the SofaPython3 by mistake and to have never worked. By looking at it it may be an experiment to allow syntax like this import Sofa.Components Sofa.Components.MechanicalObject() ... --- bindings/Sofa/CMakeLists.txt | 1 - bindings/Sofa/package/__init__.py | 1 - .../Sofa/Components/CMakeLists.txt | 21 --- .../Sofa/Components/Submodule_Components.cpp | 142 ------------------ .../Sofa/Components/Submodule_Components.h | 30 ---- 5 files changed, 195 deletions(-) delete mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Components/CMakeLists.txt delete mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Components/Submodule_Components.cpp delete mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Components/Submodule_Components.h diff --git a/bindings/Sofa/CMakeLists.txt b/bindings/Sofa/CMakeLists.txt index 9bfab5b5..63227a2b 100644 --- a/bindings/Sofa/CMakeLists.txt +++ b/bindings/Sofa/CMakeLists.txt @@ -1,7 +1,6 @@ project(Bindings.Sofa) set(SOFABINDINGS_MODULE_LIST - Components Core Helper Simulation diff --git a/bindings/Sofa/package/__init__.py b/bindings/Sofa/package/__init__.py index 2df434bc..8f6b3996 100644 --- a/bindings/Sofa/package/__init__.py +++ b/bindings/Sofa/package/__init__.py @@ -161,7 +161,6 @@ import Sofa.Core import Sofa.Simulation import Sofa.Types -import Sofa.Components import SofaTypes from .prefab import * diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Components/CMakeLists.txt b/bindings/Sofa/src/SofaPython3/Sofa/Components/CMakeLists.txt deleted file mode 100644 index 67c1e21b..00000000 --- a/bindings/Sofa/src/SofaPython3/Sofa/Components/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -project(Bindings.Sofa.Components) - -set(HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_Components.h -) - -set(SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_Components.cpp -) - -sofa_find_package(Sofa.Simulation.Core REQUIRED) - -SP3_add_python_module( - TARGET ${PROJECT_NAME} - PACKAGE Bindings.Sofa - MODULE Components - DESTINATION Sofa - SOURCES ${SOURCE_FILES} - HEADERS ${HEADER_FILES} - DEPENDS Sofa.Simulation.Core SofaPython3::Plugin -) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Components/Submodule_Components.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Components/Submodule_Components.cpp deleted file mode 100644 index 639ea6d2..00000000 --- a/bindings/Sofa/src/SofaPython3/Sofa/Components/Submodule_Components.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2021 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see <http://www.gnu.org/licenses/>. * -******************************************************************************* -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - - -#include <iostream> - -#include <sofa/core/ObjectFactory.h> -using sofa::core::objectmodel::BaseObjectDescription; -using sofa::core::ObjectFactory; - -#include <sofa/helper/logging/Messaging.h> -using sofa::helper::logging::Message; - -#include <sofa/simulation/Node.h> -using sofa::simulation::Node; - -#include <SofaPython3/DataHelper.h> -#include <SofaPython3/Sofa/Core/Binding_Base.h> -#include <SofaPython3/Sofa/Core/Binding_BaseObject.h> - -#include <sofa/core/init.h> -#include <sofa/helper/init.h> -#include <sofa/simulation/init.h> - -namespace py = pybind11; -using namespace py::literals; - -namespace sofapython3 -{ - -class FCreator -{ -public: - FCreator(const std::string& n) - { - name = n; - } - std::string name; -}; - -PYBIND11_MODULE(Components, m) -{ - // These are needed to force the dynamic loading of module dependencies (found in CMakeLists.txt) - sofa::core::init(); - sofa::helper::init(); - sofa::simulation::core::init(); - - py::class_<FCreator> mm(m, "Creator"); - mm.def("__call__", [](FCreator& s, const py::args& args, const py::kwargs& kwargs){ - if(args.size() != 1) - { - throw py::type_error("Invalid number of arguments. Only 1 argument of type 'Node' is allowed."); - } - - py::object pynode = args[0]; - if(!py::isinstance<sofa::simulation::Node>(pynode)) - { - throw py::type_error(std::string("Invalid first argument. Expecting 'Node' but got ") + py::cast<std::string>(py::str(pynode))); - } - - auto node = py::cast<py_shared_ptr<sofa::simulation::Node>>(pynode); - - /// Prepare the description to hold the different python attributes as data field's - /// arguments then create the object. - BaseObjectDescription desc {s.name.c_str(), s.name.c_str()}; - fillBaseObjectdescription(desc, kwargs); - auto object = py_shared_ptr<sofa::core::objectmodel::BaseObject>(ObjectFactory::getInstance()->createObject(node.get(), &desc)); - - /// After calling createObject the returned value can be either a nullptr - /// or non-null but with error message or non-null. - /// Let's first handle the case when the returned pointer is null. - if(!object) - { - std::stringstream tmp ; - for(auto& s : desc.getErrors()) - tmp << s << msgendl ; - throw py::value_error(tmp.str()); - } - - //checkParamUsage(object.get(), desc); - - /// Convert the logged messages in the object's internal logging into python exception. - /// this is not a very fast way to do that...but well...python is slow anyway. And serious - /// error management has a very high priority. If performance becomes an issue we will fix it - /// when needed. - if(object->countLoggedMessages({Message::Error})) - { - throw py::value_error(object->getLoggedMessagesAsString({Message::Error})); - } - - return py::cast(object); - }); - - m.def("__getattr__", [](const std::string& name) -> py::object - { - return py::cast(new FCreator(name)); - }); - - // THIS PART IS NOT WORKING... - //todo(dmarchal 04/07/2019): do it or delete it in one year. -// py::list names; -// std::vector<ObjectFactory::ClassEntry::SPtr> entries ; -// ObjectFactory::getInstance()->getAllEntries(entries) ; - -// for(auto& entry : entries) -// { -// names.append(entry->className); -// } - -// simulation.def("__dir__", []() -> py::object -// { -// py::list names; -// std::vector<ObjectFactory::ClassEntry::SPtr> entries ; -// ObjectFactory::getInstance()->getAllEntries(entries) ; - -// for(auto& entry : entries) -// { -// names.append(entry->className); -// } -// return names; //std::move(names); -// }); - -} - -} /// namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Components/Submodule_Components.h b/bindings/Sofa/src/SofaPython3/Sofa/Components/Submodule_Components.h deleted file mode 100644 index 8c22387f..00000000 --- a/bindings/Sofa/src/SofaPython3/Sofa/Components/Submodule_Components.h +++ /dev/null @@ -1,30 +0,0 @@ -/****************************************************************************** -* SOFA, Simulation Open-Framework Architecture * -* (c) 2021 INRIA, USTL, UJF, CNRS, MGH * -* * -* This program is free software; you can redistribute it and/or modify it * -* under the terms of the GNU Lesser General Public License as published by * -* the Free Software Foundation; either version 2.1 of the License, or (at * -* your option) any later version. * -* * -* This program is distributed in the hope that it will be useful, but WITHOUT * -* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * -* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * -* for more details. * -* * -* You should have received a copy of the GNU Lesser General Public License * -* along with this program. If not, see <http://www.gnu.org/licenses/>. * -******************************************************************************* -* Contact information: contact@sofa-framework.org * -******************************************************************************/ - -#pragma once - -#include <pybind11/pybind11.h> - -namespace sofapython3 -{ -namespace py { using namespace pybind11; } - -} ///namespace sofapython3 - From 1df35ab158588866e1b9bc5a582e2cc4d16fe6c6 Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Wed, 2 Oct 2024 14:21:17 +0200 Subject: [PATCH 08/20] Completion Binding_Node draft --- .../SofaPython3/Sofa/Core/Binding_Node.cpp | 318 ++++++++++++++---- .../SofaPython3/Sofa/Core/Binding_Node_doc.h | 20 +- 2 files changed, 264 insertions(+), 74 deletions(-) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp index 9c282941..c8f88d14 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp @@ -67,6 +67,8 @@ using sofa::core::objectmodel::BaseObjectDescription; #include <queue> #include <sofa/core/objectmodel/Link.h> +#include <regex> + // These two lines are there to handle deprecated version of pybind. SOFAPYTHON3_BIND_ATTRIBUTE_ERROR() SOFAPYTHON3_ADD_PYBIND_TYPE_FOR_OLD_VERSION() @@ -294,7 +296,6 @@ py::object addObjectKwargs(Node* self, const std::string& type, const py::kwargs return PythonFactory::toPython(object.get()); } -/// Implement the addObject function. py::object addObject2(Node* self, const py::type type, const py::kwargs& kwargs) { auto name = py::cast<std::string>(type.attr("__name__")); @@ -613,69 +614,270 @@ void sendEvent(Node* self, py::object pyUserData, char* eventName) sofapython3::PythonScriptEvent event(self, eventName, pyUserData); self->propagateEvent(sofa::core::execparams::defaultInstance(), &event); } - } -void moduleAddNode(py::module &m) { - /// Register the complete parent-child relationship between Base and Node to the pybind11 - /// typing system. - py::class_<sofa::core::objectmodel::BaseNode, - sofa::core::objectmodel::Base, - py_shared_ptr<sofa::core::objectmodel::BaseNode>>(m, "BaseNode"); - - py::class_<Node, sofa::core::objectmodel::BaseNode, - sofa::core::objectmodel::Context, py_shared_ptr<Node>> - p(m, "Node", sofapython3::doc::sofa::core::Node::Class); - - PythonFactory::registerType<sofa::simulation::graph::DAGNode>( - [](sofa::core::objectmodel::Base* object) + +/// Implement the addObject function. +template<typename T> +class PythonMethod +{ +public: + PythonMethod(std::function<T> cb) + { + function = cb; + } + std::string signature = "def addObject(int, char*) -> T"; + std::string docstring = "Adding an object"; + std::function<T> function; +}; + +PythonMethod<decltype(addObjectKwargs)> addObject1 { &addObjectKwargs }; + +template<class T> +class def_method; + +//template<typename T> +//PyOverride<T> def_override(T& classI, const std::string& name_) +//{ +// PyOverride<T> tmp {classI, name_ }; +// return tmp; +//} + +template<typename Class> +class def_method +{ +public: + std::stringstream tmp; + int i=1; + Class classInstance; + py::options options; + std::string name; + std::string previous; + std::vector<std::string> signatures; + std::vector<std::string> docstrings; +public: + def_method(Class classI, const std::string& name_) : + classInstance(classI), name(name_) + { + } + + void parse_docstring() + { + save_docstring(); + std::smatch m; + std::string last; + std::regex e; + + if(signatures.size()==1) + { + //e = std::regex(".+"); + return; + } + + int idx = 0; + std::cout << previous << std::endl; + e = std::regex("(\\d+\\D )(.*)"); + while (std::regex_search (previous, m,e)) + { + for (auto x:m){ + last = x; + std::cout << "Mathc " << last << std::endl; + } + signatures[idx] = last; + if(idx>0) + docstrings[idx-1] = m.prefix().str(); + idx++; + previous = m.suffix().str(); + + e = std::regex("("+std::to_string(idx+1)+". )("+name+".*)"); + } + if(!previous.empty()) + docstrings[idx] = m.prefix().str(); + } + + template<typename T> + def_method& add_override(T function, const std::string& docstring) + { + i++; + classInstance.def(name.c_str(), function, docstring.c_str()); + + save_docstring(); + + std::smatch m; + std::string last; + std::regex e; + if(i==2) + e =std::regex(".+"); + else + e = std::regex("(\\d+\\D )(.*)"); + + while (std::regex_search (previous,m,e)) + { + for (auto x:m) + last = x; + //std::cout << "PREFIX IS " << m.prefix().str() << std::endl; + previous = m.suffix().str(); + } + + signatures.push_back(""); + docstrings.push_back(""); + + build_and_patch_docstring(); + + return *this; + } + + template<typename T> + def_method& add_override(const std::string& signature, T function, const std::string& docstring) { - return py::cast(dynamic_cast<Node*>(object->toBaseNode())); - }); + i++; + classInstance.def(name.c_str(), function, docstring.c_str()); - 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("init", &init, sofapython3::doc::sofa::core::Node::initSofa ); - p.def("add", &addKwargs, sofapython3::doc::sofa::core::Node::addKwargs); + signatures.push_back(signature); + docstrings.push_back(""); + build_and_patch_docstring(); + return *this; + } + + void set() { - py::options options; - options.disable_function_signatures(); - - p.def("addObject", &addObject2, sofapython3::doc::sofa::core::Node::addObject2); - p.def("addObject", &addObjectKwargs, sofapython3::doc::sofa::core::Node::addObjectKwargs); - p.def("addObject", &addObject, sofapython3::doc::sofa::core::Node::addObject, py::keep_alive<0, 2>()); - } - - p.def("createObject", &createObject, sofapython3::doc::sofa::core::Node::createObject, py::keep_alive<0, 2>()); - p.def("hasObject", &hasObject, sofapython3::doc::sofa::core::Node::hasObject); - p.def("getObject", &getObject, sofapython3::doc::sofa::core::Node::getObject); - p.def("addChild", &addChildKwargs, sofapython3::doc::sofa::core::Node::addChildKwargs); - p.def("addChild", &addChild, sofapython3::doc::sofa::core::Node::addChild, py::keep_alive<0, 2>()); - p.def("createChild", &createChild, sofapython3::doc::sofa::core::Node::createChild, py::keep_alive<0, 2>()); - p.def("getChild", &getChild, sofapython3::doc::sofa::core::Node::getChild); - p.def("removeChild", &removeChild, sofapython3::doc::sofa::core::Node::removeChild); - p.def("removeChild", &removeChildByName, sofapython3::doc::sofa::core::Node::removeChildWithName); - p.def("getRoot", &getRoot, sofapython3::doc::sofa::core::Node::getRoot); - p.def("getPathName", &Node::getPathName, sofapython3::doc::sofa::core::Node::getPathName); - p.def("getLinkPath", &getLinkPath, sofapython3::doc::sofa::core::Node::getLinkPath); - p.def_property_readonly("children", &property_children, sofapython3::doc::sofa::core::Node::children); - p.def_property_readonly("parents", &property_parents, sofapython3::doc::sofa::core::Node::parents); - p.def_property_readonly("objects", &property_objects, sofapython3::doc::sofa::core::Node::objects); - p.def("__getattr__", &__getattr__); - p.def("__getitem__", &__getitem__); - p.def("removeObject", &removeObject, sofapython3::doc::sofa::core::Node::removeObject); - p.def("getRootPath", &Node::getRootPath, sofapython3::doc::sofa::core::Node::getRootPath); - p.def("moveChild", &moveChild, sofapython3::doc::sofa::core::Node::moveChild); - p.def("isInitialized", &Node::isInitialized, sofapython3::doc::sofa::core::Node::isInitialized); - p.def("getAsACreateObjectParameter", &getLinkPath, sofapython3::doc::sofa::core::Node::getAsACreateObjectParameter); - p.def("detachFromGraph", &Node::detachFromGraph, sofapython3::doc::sofa::core::Node::detachFromGraph); - p.def("getMass", &getMass, sofapython3::doc::sofa::core::Node::getMass); - p.def("hasODESolver", &hasODESolver, sofapython3::doc::sofa::core::Node::hasODESolver); - p.def("getForceField", &getForceField, sofapython3::doc::sofa::core::Node::getForceField); - p.def("getMechanicalState", &getMechanicalState, sofapython3::doc::sofa::core::Node::getMechanicalState); - p.def("getMechanicalMapping", &getMechanicalMapping, sofapython3::doc::sofa::core::Node::getMechanicalMapping); - p.def("sendEvent", &sendEvent, sofapython3::doc::sofa::core::Node::sendEvent); + parse_docstring(); + build_and_patch_docstring(); + } + + void save_docstring(){ + // get the raw python object out of the classInstance + auto method = classInstance.attr(name.c_str()).ptr(); + // if it is an instance method get the raw CFunction + if(Py_TYPE(method) == &PyInstanceMethod_Type){ + method = ((PyInstanceMethodObject*)(method))->func; + } + // if it is a CFunction, get its docstring + if(Py_TYPE(method) == &PyCFunction_Type){ + auto cmethod = (PyCFunctionObject*)method; + previous = std::string(cmethod->m_ml->ml_doc); + } + } + + void build_and_patch_docstring() + { + std::stringstream tmp; + if(signatures.size() == 1) + { + tmp << signatures[0] << "\n\n"; + tmp << docstrings[0] << "\n\n"; + } + else + { + tmp << name <<"(*args, **kwargs)\n"; + tmp << "Overloaded function.\n\n"; + } + for(unsigned int i=0;i<docstrings.size();i++) + { + tmp << (i+1) << ". " << signatures[i] << "\n\n"; + tmp << docstrings[i] << "\n\n"; + } + replace_docstring(tmp.str()); + } + + + void replace_docstring(const std::string& docstring){ + // get the raw python object out of the classInstance + auto method = classInstance.attr(name.c_str()).ptr(); + // if it is an instance method get the raw CFunction + if(Py_TYPE(method) == &PyInstanceMethod_Type){ + method = ((PyInstanceMethodObject*)(method))->func; + } + // if it is a CFunction, get its docstring + if(Py_TYPE(method) == &PyCFunction_Type){ + auto cmethod = (PyCFunctionObject*)method; + cmethod->m_ml->ml_doc = strdup(docstring.c_str()); + } + } + +}; + +void moduleAddNode(py::module &m) { + { + /// Register the complete parent-child relationship between Base and Node to the pybind11 + /// typing system. + py::class_<sofa::core::objectmodel::BaseNode, + sofa::core::objectmodel::Base, + py_shared_ptr<sofa::core::objectmodel::BaseNode>>(m, "BaseNode"); + + py::class_<Node, sofa::core::objectmodel::BaseNode, + sofa::core::objectmodel::Context, py_shared_ptr<Node>> + p(m, "Node", sofapython3::doc::sofa::core::Node::Class); + + PythonFactory::registerType<sofa::simulation::graph::DAGNode>( + [](sofa::core::objectmodel::Base* object) + { + return py::cast(dynamic_cast<Node*>(object->toBaseNode())); + }); + + 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("init", &init, sofapython3::doc::sofa::core::Node::initSofa ); + p.def("add", &addKwargs, sofapython3::doc::sofa::core::Node::addKwargs); + + def_method(p, "addObject") + .add_override(addObjectKwargs, sofapython3::doc::sofa::core::Node::addObjectKwargs) + .add_override(addObject, sofapython3::doc::sofa::core::Node::addObject) + .add_override("def addObject1[T]() -> T", addObjectKwargs, "Magic function") + .add_override(addObjectKwargs,"An other one") + .set(); + + // p.def("addObject", &addObjectKwargs); + // auto method = p.attr("addObject").ptr(); + // if(Py_TYPE(method) == &PyInstanceMethod_Type){ + // method = ((PyInstanceMethodObject*)(method))->func; + // } + // if(Py_TYPE(method) == &PyCFunction_Type){ + // auto cmethod = (PyCFunctionObject*)method; + // std::cout<< "STEP 1: " << cmethod->m_ml->ml_doc << std::endl;; + // } + + // p.def("addObject", &addObject, py::keep_alive<0, 2>()); + // method = p.attr("addObject").ptr(); + // if(Py_TYPE(method) == &PyInstanceMethod_Type){ + // method = ((PyInstanceMethodObject*)(method))->func; + // } + // if(Py_TYPE(method) == &PyCFunction_Type){ + // auto cmethod = (PyCFunctionObject*)method; + // std::cout<< "STEP 2: " << cmethod->m_ml->ml_doc << std::endl;; + // } + + p.def("createObject", &createObject, sofapython3::doc::sofa::core::Node::createObject, py::keep_alive<0, 2>()); + p.def("hasObject", &hasObject, sofapython3::doc::sofa::core::Node::hasObject); + p.def("getObject", &getObject, sofapython3::doc::sofa::core::Node::getObject); + p.def("addChild", &addChildKwargs, sofapython3::doc::sofa::core::Node::addChildKwargs); + p.def("addChild", &addChild, sofapython3::doc::sofa::core::Node::addChild, py::keep_alive<0, 2>()); + p.def("createChild", &createChild, sofapython3::doc::sofa::core::Node::createChild, py::keep_alive<0, 2>()); + p.def("getChild", &getChild, sofapython3::doc::sofa::core::Node::getChild); + p.def("removeChild", &removeChild, sofapython3::doc::sofa::core::Node::removeChild); + p.def("removeChild", &removeChildByName, sofapython3::doc::sofa::core::Node::removeChildWithName); + p.def("getRoot", &getRoot, sofapython3::doc::sofa::core::Node::getRoot); + p.def("getPathName", &Node::getPathName, sofapython3::doc::sofa::core::Node::getPathName); + p.def("getLinkPath", &getLinkPath, sofapython3::doc::sofa::core::Node::getLinkPath); + p.def_property_readonly("children", &property_children, sofapython3::doc::sofa::core::Node::children); + p.def_property_readonly("parents", &property_parents, sofapython3::doc::sofa::core::Node::parents); + p.def_property_readonly("objects", &property_objects, sofapython3::doc::sofa::core::Node::objects); + p.def("__getattr__", &__getattr__); + p.def("__getitem__", &__getitem__); + p.def("removeObject", &removeObject, sofapython3::doc::sofa::core::Node::removeObject); + p.def("getRootPath", &Node::getRootPath, sofapython3::doc::sofa::core::Node::getRootPath); + p.def("moveChild", &moveChild, sofapython3::doc::sofa::core::Node::moveChild); + p.def("isInitialized", &Node::isInitialized, sofapython3::doc::sofa::core::Node::isInitialized); + p.def("getAsACreateObjectParameter", &getLinkPath, sofapython3::doc::sofa::core::Node::getAsACreateObjectParameter); + p.def("detachFromGraph", &Node::detachFromGraph, sofapython3::doc::sofa::core::Node::detachFromGraph); + p.def("getMass", &getMass, sofapython3::doc::sofa::core::Node::getMass); + p.def("hasODESolver", &hasODESolver, sofapython3::doc::sofa::core::Node::hasODESolver); + p.def("getForceField", &getForceField, sofapython3::doc::sofa::core::Node::getForceField); + p.def("getMechanicalState", &getMechanicalState, sofapython3::doc::sofa::core::Node::getMechanicalState); + p.def("getMechanicalMapping", &getMechanicalMapping, sofapython3::doc::sofa::core::Node::getMechanicalMapping); + p.def("sendEvent", &sendEvent, sofapython3::doc::sofa::core::Node::sendEvent); + } } } /// namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node_doc.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node_doc.h index 36c48f7f..aa843e9a 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node_doc.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node_doc.h @@ -128,28 +128,16 @@ static auto addObject2 = R"(addObject(*args, **kwargs) Overloaded function. -1. addObject(self: Sofa.Core.Node, arg0: str, **kwargs) -> Sofa.Core.Object +1. addObject[T](self, component_type: T, parameters: dict) -> T -Add an object a real type +The 3.12 version of types... COUCOUC ON SE MARRE -2. addObject(self, arg0: type[T], **kwargs) -> T +2. addObject(self, component_type: Base, parameters: float) -> Tobject -The dirty trick - - -3. addObject(self, arg0: type[T], dict) -> T - - -The dirty trick to get parameters input. - - -4. addObject[T](self, component_type: T, parameters: dict) -> T - - -The 3.12 version of types... +The 3.12 version of types... COUCOUC ON SE MARRE 2 )"; From 992fb0ea5611b37bdfbf1d898d562b36a7afe673 Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Wed, 2 Oct 2024 16:42:52 +0200 Subject: [PATCH 09/20] First working version --- Plugin/CMakeLists.txt | 1 + Plugin/src/SofaPython3/PyBindHelper.h | 190 +++++++++++++++ .../SofaPython3/Sofa/Core/Binding_Node.cpp | 216 +----------------- .../SofaPython3/Sofa/Core/Binding_Node_doc.h | 45 ++-- 4 files changed, 211 insertions(+), 241 deletions(-) create mode 100644 Plugin/src/SofaPython3/PyBindHelper.h diff --git a/Plugin/CMakeLists.txt b/Plugin/CMakeLists.txt index f53e987a..b2b1aabc 100644 --- a/Plugin/CMakeLists.txt +++ b/Plugin/CMakeLists.txt @@ -4,6 +4,7 @@ set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/initModule.h ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/PythonEnvironment.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/PyBindHelper.h ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/SceneLoaderPY3.h ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/SpellingSuggestionHelper.h diff --git a/Plugin/src/SofaPython3/PyBindHelper.h b/Plugin/src/SofaPython3/PyBindHelper.h new file mode 100644 index 00000000..e8a5787b --- /dev/null +++ b/Plugin/src/SofaPython3/PyBindHelper.h @@ -0,0 +1,190 @@ +/****************************************************************************** +* SofaPython3 plugin * +* (c) 2021 CNRS, University of Lille, INRIA * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see <http://www.gnu.org/licenses/>. * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once + +#include <SofaPython3/config.h> +#include <sofa/helper/logging/Messaging.h> +#include <string> +#include <vector> +#include <regex> +#include <pybind11/pybind11.h> + +namespace sofapython3 +{ + +class PythonMethodDescription +{ +public: + void add_entry(const std::string& signature="") + { + signatures.push_back(signature); + docstrings.push_back(""); + } + + /// Parse the docstring generated by pybind11 to extract the different method signatures + /// and for each the associated docstring. + void parse_docstring(const std::string& name, std::string docstring) + { + std::smatch m; + std::string last; + std::regex e; + + if(signatures.size()==0) + return; + + // easy path. Take the signature, then consider the remaining as a docstring + if(signatures.size()==1) + { + e = std::regex("("+name+".*)"); + if (std::regex_search (docstring, m,e)) + { + for (auto x:m) + last = x; + if(signatures[0].size()==0) + signatures[0] = last; + docstrings[0] = m.suffix().str(); + } + return; + } + + int idx = 0; + e = std::regex("(1\\. )("+name+".*)"); + while (std::regex_search (docstring, m,e)) + { + for (auto x:m) + last = x; + + if(signatures[idx].size()==0) + signatures[idx] = last; + + if(idx>0) + docstrings[idx-1] = m.prefix().str(); + idx++; + docstring = m.suffix().str(); + + auto pex = "("+std::to_string(idx+1)+"\\. )("+name+".*)"; + e = std::regex(pex); + } + if(!docstring.empty()) + docstrings[idx-1] = docstring; + } + + /// Generates the docstring from the extracted ones from pybind11 and applying the + /// customs signatures, if any. + const std::string build_docstring(const std::string& name) const + { + std::stringstream tmp; + if(signatures.size() == 1) + { + tmp << signatures[0]; + tmp << docstrings[0]; + return tmp.str(); + } + else + { + tmp << name <<"(*args, **kwargs)\n"; + tmp << "Overloaded function.\n\n"; + } + for(unsigned int i=0;i<docstrings.size();i++) + { + tmp << (i+1) << ". " << signatures[i] ; + tmp << docstrings[i] ; + } + return tmp.str(); + } + +private: + std::vector<std::string> signatures; //< signatures for the method overrides + std::vector<std::string> docstrings; //< docstrings for the method overrides + +}; + +template<typename Class> +class def_method +{ +public: + def_method(Class classI, const std::string& name_) : + classInstance(classI), name(name_) + { + } + + virtual ~def_method() + { + description.parse_docstring(name, get_current_docstring()); + set_docstring(description.build_docstring(name)); + } + + template<typename ... Args> + def_method& add_override(Args ... args) + { + classInstance.def(name.c_str(), args...); + description.add_entry(); + return *this; + } + + template<typename ... Args> + def_method& add_override(const char* signature, Args ... args) + { + classInstance.def(name.c_str(), args...); + description.add_entry(signature); + return *this; + } + + std::string get_current_docstring() const { + std::string tmp; + // get the raw python object out of the classInstance + auto method = classInstance.attr(name.c_str()).ptr(); + // if it is an instance method get the raw CFunction + if(Py_TYPE(method) == &PyInstanceMethod_Type){ + method = ((PyInstanceMethodObject*)(method))->func; + } + // if it is a CFunction, get its docstring + if(Py_TYPE(method) == &PyCFunction_Type){ + auto cmethod = (PyCFunctionObject*)method; + tmp = std::string(cmethod->m_ml->ml_doc); + } + return tmp; + } + + void set_docstring(const std::string& docstring) const + { + // get the raw python object out of the classInstance + auto method = classInstance.attr(name.c_str()).ptr(); + // if it is an instance method get the raw CFunction + if(Py_TYPE(method) == &PyInstanceMethod_Type){ + method = ((PyInstanceMethodObject*)(method))->func; + } + // if it is a CFunction, get its docstring + if(Py_TYPE(method) == &PyCFunction_Type){ + auto cmethod = (PyCFunctionObject*)method; + cmethod->m_ml->ml_doc = strdup(docstring.c_str()); + }else + { + msg_error("SofaPython3") << "Unable to build docstring for method " << name; + } + } + +private: + Class classInstance; //< stores the pybind::class_<XXX, > + std::string name; //< stores the name of the method we declares + PythonMethodDescription description; +}; + +} diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp index c8f88d14..5ecae143 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp @@ -61,14 +61,13 @@ using sofapython3::PythonEnvironment; #include <SofaPython3/Sofa/Core/Binding_PythonScriptEvent.h> #include <SofaPython3/SpellingSuggestionHelper.h> +#include <SofaPython3/PyBindHelper.h> using sofa::core::objectmodel::BaseObjectDescription; #include <queue> #include <sofa/core/objectmodel/Link.h> -#include <regex> - // These two lines are there to handle deprecated version of pybind. SOFAPYTHON3_BIND_ATTRIBUTE_ERROR() SOFAPYTHON3_ADD_PYBIND_TYPE_FOR_OLD_VERSION() @@ -296,10 +295,9 @@ py::object addObjectKwargs(Node* self, const std::string& type, const py::kwargs return PythonFactory::toPython(object.get()); } -py::object addObject2(Node* self, const py::type type, const py::kwargs& kwargs) +py::object addObjectGenericType(Node* self, const py::type type, const py::kwargs& kwargs) { auto name = py::cast<std::string>(type.attr("__name__")); - std::cout << "PATH TO CREATE AN OBJECT OF T>YPE 2 " << name << std::endl; return addObjectKwargs(self, name, kwargs); } @@ -616,188 +614,6 @@ void sendEvent(Node* self, py::object pyUserData, char* eventName) } } - -/// Implement the addObject function. -template<typename T> -class PythonMethod -{ -public: - PythonMethod(std::function<T> cb) - { - function = cb; - } - std::string signature = "def addObject(int, char*) -> T"; - std::string docstring = "Adding an object"; - std::function<T> function; -}; - -PythonMethod<decltype(addObjectKwargs)> addObject1 { &addObjectKwargs }; - -template<class T> -class def_method; - -//template<typename T> -//PyOverride<T> def_override(T& classI, const std::string& name_) -//{ -// PyOverride<T> tmp {classI, name_ }; -// return tmp; -//} - -template<typename Class> -class def_method -{ -public: - std::stringstream tmp; - int i=1; - Class classInstance; - py::options options; - std::string name; - std::string previous; - std::vector<std::string> signatures; - std::vector<std::string> docstrings; -public: - def_method(Class classI, const std::string& name_) : - classInstance(classI), name(name_) - { - } - - void parse_docstring() - { - save_docstring(); - std::smatch m; - std::string last; - std::regex e; - - if(signatures.size()==1) - { - //e = std::regex(".+"); - return; - } - - int idx = 0; - std::cout << previous << std::endl; - e = std::regex("(\\d+\\D )(.*)"); - while (std::regex_search (previous, m,e)) - { - for (auto x:m){ - last = x; - std::cout << "Mathc " << last << std::endl; - } - signatures[idx] = last; - if(idx>0) - docstrings[idx-1] = m.prefix().str(); - idx++; - previous = m.suffix().str(); - - e = std::regex("("+std::to_string(idx+1)+". )("+name+".*)"); - } - if(!previous.empty()) - docstrings[idx] = m.prefix().str(); - } - - template<typename T> - def_method& add_override(T function, const std::string& docstring) - { - i++; - classInstance.def(name.c_str(), function, docstring.c_str()); - - save_docstring(); - - std::smatch m; - std::string last; - std::regex e; - if(i==2) - e =std::regex(".+"); - else - e = std::regex("(\\d+\\D )(.*)"); - - while (std::regex_search (previous,m,e)) - { - for (auto x:m) - last = x; - //std::cout << "PREFIX IS " << m.prefix().str() << std::endl; - previous = m.suffix().str(); - } - - signatures.push_back(""); - docstrings.push_back(""); - - build_and_patch_docstring(); - - return *this; - } - - template<typename T> - def_method& add_override(const std::string& signature, T function, const std::string& docstring) - { - i++; - classInstance.def(name.c_str(), function, docstring.c_str()); - - signatures.push_back(signature); - docstrings.push_back(""); - - build_and_patch_docstring(); - return *this; - } - - void set() - { - parse_docstring(); - build_and_patch_docstring(); - } - - void save_docstring(){ - // get the raw python object out of the classInstance - auto method = classInstance.attr(name.c_str()).ptr(); - // if it is an instance method get the raw CFunction - if(Py_TYPE(method) == &PyInstanceMethod_Type){ - method = ((PyInstanceMethodObject*)(method))->func; - } - // if it is a CFunction, get its docstring - if(Py_TYPE(method) == &PyCFunction_Type){ - auto cmethod = (PyCFunctionObject*)method; - previous = std::string(cmethod->m_ml->ml_doc); - } - } - - void build_and_patch_docstring() - { - std::stringstream tmp; - if(signatures.size() == 1) - { - tmp << signatures[0] << "\n\n"; - tmp << docstrings[0] << "\n\n"; - } - else - { - tmp << name <<"(*args, **kwargs)\n"; - tmp << "Overloaded function.\n\n"; - } - for(unsigned int i=0;i<docstrings.size();i++) - { - tmp << (i+1) << ". " << signatures[i] << "\n\n"; - tmp << docstrings[i] << "\n\n"; - } - replace_docstring(tmp.str()); - } - - - void replace_docstring(const std::string& docstring){ - // get the raw python object out of the classInstance - auto method = classInstance.attr(name.c_str()).ptr(); - // if it is an instance method get the raw CFunction - if(Py_TYPE(method) == &PyInstanceMethod_Type){ - method = ((PyInstanceMethodObject*)(method))->func; - } - // if it is a CFunction, get its docstring - if(Py_TYPE(method) == &PyCFunction_Type){ - auto cmethod = (PyCFunctionObject*)method; - cmethod->m_ml->ml_doc = strdup(docstring.c_str()); - } - } - -}; - void moduleAddNode(py::module &m) { { /// Register the complete parent-child relationship between Base and Node to the pybind11 @@ -822,31 +638,9 @@ void moduleAddNode(py::module &m) { p.def("add", &addKwargs, sofapython3::doc::sofa::core::Node::addKwargs); def_method(p, "addObject") - .add_override(addObjectKwargs, sofapython3::doc::sofa::core::Node::addObjectKwargs) - .add_override(addObject, sofapython3::doc::sofa::core::Node::addObject) - .add_override("def addObject1[T]() -> T", addObjectKwargs, "Magic function") - .add_override(addObjectKwargs,"An other one") - .set(); - - // p.def("addObject", &addObjectKwargs); - // auto method = p.attr("addObject").ptr(); - // if(Py_TYPE(method) == &PyInstanceMethod_Type){ - // method = ((PyInstanceMethodObject*)(method))->func; - // } - // if(Py_TYPE(method) == &PyCFunction_Type){ - // auto cmethod = (PyCFunctionObject*)method; - // std::cout<< "STEP 1: " << cmethod->m_ml->ml_doc << std::endl;; - // } - - // p.def("addObject", &addObject, py::keep_alive<0, 2>()); - // method = p.attr("addObject").ptr(); - // if(Py_TYPE(method) == &PyInstanceMethod_Type){ - // method = ((PyInstanceMethodObject*)(method))->func; - // } - // if(Py_TYPE(method) == &PyCFunction_Type){ - // auto cmethod = (PyCFunctionObject*)method; - // std::cout<< "STEP 2: " << cmethod->m_ml->ml_doc << std::endl;; - // } + .add_override(addObjectKwargs, sofapython3::doc::sofa::core::Node::addObjectKwargs) + .add_override(addObject, sofapython3::doc::sofa::core::Node::addObject) + .add_override("def addObject[T]() -> T", addObjectGenericType, sofapython3::doc::sofa::core::Node::addObjectGenerictype); p.def("createObject", &createObject, sofapython3::doc::sofa::core::Node::createObject, py::keep_alive<0, 2>()); p.def("hasObject", &hasObject, sofapython3::doc::sofa::core::Node::hasObject); diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node_doc.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node_doc.h index aa843e9a..1aa62f97 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node_doc.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node_doc.h @@ -84,8 +84,8 @@ static auto Class = # fast access. n["child1.child2.dofs.position"] - )"; + static auto init = R"( Initialize the components of this node and all the nodes which depend on it. @@ -123,45 +123,30 @@ static auto addKwargs = node.add(Cube, name="MyCube"") )"; - -static auto addObject2 = - R"(addObject(*args, **kwargs) -Overloaded function. - -1. addObject[T](self, component_type: T, parameters: dict) -> T - - -The 3.12 version of types... COUCOUC ON SE MARRE - - -2. addObject(self, component_type: Base, parameters: float) -> Tobject - - -The 3.12 version of types... COUCOUC ON SE MARRE 2 - - -)"; - static auto addObjectKwargs = R"( - Add an object. + Creates and add a new sofa object to the node. Detect the implemented interfaces and add the object to the corresponding lists. :param self: the node itself - :param type: type of the object - :param kwargs - :type self: Sofa.Simulation.Node* - :type type: string& - :type kwargs: kwargs& + :param typename: name of the type of the object to create + :param kwargs: extra parameteres to initialize the created object. + )"; + +static auto addObjectGenerictype = + R"( + Creates and add a new sofa object to the node. + :param self: the node itself + :param type: the component's type to add, type's name is used as sofa factory's type name + :return: the created component )"; static auto addObject = R"( - Add an object. + Adds an existing object to the node. Detect the implemented interfaces and add the object to the corresponding lists. :param self: the node itself - :param object: the object to be added - :type self: Sofa.Simulation.Node& - :type object: Sofa.Simulation.BaseObject* + :param object: the component to add + :return: the added component )"; static auto createObject = From 7d4549e9c2de50e9e2392e6b6f4b0a804ef39e8c Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Wed, 2 Oct 2024 17:14:43 +0200 Subject: [PATCH 10/20] FIXUP --- bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp index 5ecae143..b1da0e8b 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp @@ -640,7 +640,7 @@ void moduleAddNode(py::module &m) { def_method(p, "addObject") .add_override(addObjectKwargs, sofapython3::doc::sofa::core::Node::addObjectKwargs) .add_override(addObject, sofapython3::doc::sofa::core::Node::addObject) - .add_override("def addObject[T]() -> T", addObjectGenericType, sofapython3::doc::sofa::core::Node::addObjectGenerictype); + .add_override("addObject[T]() -> T", addObjectGenericType, sofapython3::doc::sofa::core::Node::addObjectGenerictype); p.def("createObject", &createObject, sofapython3::doc::sofa::core::Node::createObject, py::keep_alive<0, 2>()); p.def("hasObject", &hasObject, sofapython3::doc::sofa::core::Node::hasObject); From 4894b15346a1b07ea48fe6255dbdfe5f83be133d Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Wed, 2 Oct 2024 17:17:09 +0200 Subject: [PATCH 11/20] FIXUP 2 --- bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp index b1da0e8b..fa07666f 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp @@ -640,7 +640,7 @@ void moduleAddNode(py::module &m) { def_method(p, "addObject") .add_override(addObjectKwargs, sofapython3::doc::sofa::core::Node::addObjectKwargs) .add_override(addObject, sofapython3::doc::sofa::core::Node::addObject) - .add_override("addObject[T]() -> T", addObjectGenericType, sofapython3::doc::sofa::core::Node::addObjectGenerictype); + .add_override("addObject[T](self) -> T", addObjectGenericType, sofapython3::doc::sofa::core::Node::addObjectGenerictype); p.def("createObject", &createObject, sofapython3::doc::sofa::core::Node::createObject, py::keep_alive<0, 2>()); p.def("hasObject", &hasObject, sofapython3::doc::sofa::core::Node::hasObject); From dd119b7655a1e1b21391a55dc4d3e4d6911ef8bd Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Fri, 11 Oct 2024 16:57:35 +0200 Subject: [PATCH 12/20] WIP --- bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp | 6 ++++-- 1 file changed, 4 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 fa07666f..af2907ff 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp @@ -638,9 +638,11 @@ void moduleAddNode(py::module &m) { p.def("add", &addKwargs, sofapython3::doc::sofa::core::Node::addKwargs); def_method(p, "addObject") - .add_override(addObjectKwargs, sofapython3::doc::sofa::core::Node::addObjectKwargs) + .add_override("addObject(self, typename: str, **kwargs) -> Sofa.Core.Object", + addObjectKwargs, sofapython3::doc::sofa::core::Node::addObjectKwargs) .add_override(addObject, sofapython3::doc::sofa::core::Node::addObject) - .add_override("addObject[T](self) -> T", addObjectGenericType, sofapython3::doc::sofa::core::Node::addObjectGenerictype); + .add_override("addObject[T](self, type_: type, **kwargs) -> T", + addObjectGenericType, sofapython3::doc::sofa::core::Node::addObjectGenerictype); p.def("createObject", &createObject, sofapython3::doc::sofa::core::Node::createObject, py::keep_alive<0, 2>()); p.def("hasObject", &hasObject, sofapython3::doc::sofa::core::Node::hasObject); From 8446233cb3cd3c4804cb5c1ade20e96fb4ae63b1 Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Fri, 11 Oct 2024 17:00:49 +0200 Subject: [PATCH 13/20] Update tests to take into account removal of Sofa.Components. --- .../tests/SofaConstraintSolver/matrix_access.py | 1 - .../Modules/tests/SofaLinearSolver/matrix_access.py | 1 - bindings/Sofa/Bindings.SofaConfig.cmake.in | 2 +- bindings/Sofa/tests/CMakeLists.txt | 1 - bindings/Sofa/tests/Components/Components.py | 13 ------------- 5 files changed, 1 insertion(+), 17 deletions(-) delete mode 100644 bindings/Sofa/tests/Components/Components.py diff --git a/bindings/Modules/tests/SofaConstraintSolver/matrix_access.py b/bindings/Modules/tests/SofaConstraintSolver/matrix_access.py index 1a8dacdc..d4a7f289 100644 --- a/bindings/Modules/tests/SofaConstraintSolver/matrix_access.py +++ b/bindings/Modules/tests/SofaConstraintSolver/matrix_access.py @@ -1,6 +1,5 @@ import unittest import Sofa.Core -import Sofa.Components from Sofa import SofaConstraintSolver class Test(unittest.TestCase): diff --git a/bindings/Modules/tests/SofaLinearSolver/matrix_access.py b/bindings/Modules/tests/SofaLinearSolver/matrix_access.py index 0bb0618c..09698bd2 100644 --- a/bindings/Modules/tests/SofaLinearSolver/matrix_access.py +++ b/bindings/Modules/tests/SofaLinearSolver/matrix_access.py @@ -1,6 +1,5 @@ import unittest import Sofa.Core -import Sofa.Components from Sofa import SofaLinearSolver class Test(unittest.TestCase): diff --git a/bindings/Sofa/Bindings.SofaConfig.cmake.in b/bindings/Sofa/Bindings.SofaConfig.cmake.in index c9f25fd6..86489214 100644 --- a/bindings/Sofa/Bindings.SofaConfig.cmake.in +++ b/bindings/Sofa/Bindings.SofaConfig.cmake.in @@ -8,7 +8,7 @@ find_package(SofaPython3 QUIET REQUIRED COMPONENTS Plugin) # Required by Bindings.Sofa.Helper, Bindings.Sofa.Types find_package(Sofa.Core QUIET REQUIRED) -# Required by Bindings.Sofa.Core, Bindings.Sofa.Components +# Required by Bindings.Sofa.Core find_package(Sofa.Simulation.Core QUIET REQUIRED) # Required by Bindings.Sofa.Core diff --git a/bindings/Sofa/tests/CMakeLists.txt b/bindings/Sofa/tests/CMakeLists.txt index 36d74080..2e30bd5d 100644 --- a/bindings/Sofa/tests/CMakeLists.txt +++ b/bindings/Sofa/tests/CMakeLists.txt @@ -10,7 +10,6 @@ set(SOURCE_FILES ) set(PYTHON_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Components/Components.py ${CMAKE_CURRENT_SOURCE_DIR}/Core/Base.py ${CMAKE_CURRENT_SOURCE_DIR}/Core/BaseData.py ${CMAKE_CURRENT_SOURCE_DIR}/Core/BaseLink.py diff --git a/bindings/Sofa/tests/Components/Components.py b/bindings/Sofa/tests/Components/Components.py deleted file mode 100644 index d51891d4..00000000 --- a/bindings/Sofa/tests/Components/Components.py +++ /dev/null @@ -1,13 +0,0 @@ -# coding: utf8 - -import Sofa.Core -import Sofa.Components -import unittest - -class Test(unittest.TestCase): - def test_component_creation(self): - root = Sofa.Core.Node("rootNode") - root.addObject('RequiredPlugin', name='Sofa.Component.StateContainer') - - c = Sofa.Components.MechanicalObject(root, name="dofs") - self.assertTrue(c.name.value == "dofs") From 3a8efead2b40b7cd82b29d473ec557b9d0fedbf7 Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Mon, 14 Oct 2024 15:47:26 +0200 Subject: [PATCH 14/20] FIXUP --- bindings/Sofa/tests/CMakeLists.txt | 1 - bindings/Sofa/tests/PythonModule_Sofa_test.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/bindings/Sofa/tests/CMakeLists.txt b/bindings/Sofa/tests/CMakeLists.txt index 2e30bd5d..038c1cf0 100644 --- a/bindings/Sofa/tests/CMakeLists.txt +++ b/bindings/Sofa/tests/CMakeLists.txt @@ -50,7 +50,6 @@ sofa_auto_set_target_rpath( add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) set(DIR_BINDING_LIST - Components Core Helper Simulation diff --git a/bindings/Sofa/tests/PythonModule_Sofa_test.cpp b/bindings/Sofa/tests/PythonModule_Sofa_test.cpp index 4ddc5bf3..9d80485e 100644 --- a/bindings/Sofa/tests/PythonModule_Sofa_test.cpp +++ b/bindings/Sofa/tests/PythonModule_Sofa_test.cpp @@ -58,7 +58,6 @@ static struct PythonModule_Sofa_tests : public PythonTestExtractor addTestDirectory(executable_directory+"/Bindings.Sofa.Tests.d/Helper", "Sofa_Helper_"); addTestDirectory(executable_directory+"/Bindings.Sofa.Tests.d/Simulation", "Sofa_Simulation_"); addTestDirectory(executable_directory+"/Bindings.Sofa.Tests.d/Types", "Sofa_Types_"); - addTestDirectory(executable_directory+"/Bindings.Sofa.Tests.d/Components", "Sofa_Components_"); } } python_tests; From 6cce21c6b42564d040eb799c7740b9792d716f56 Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Thu, 17 Oct 2024 11:30:52 +0200 Subject: [PATCH 15/20] Add binding for BaseClass It should be completed if ones want more feature than just class declaration --- .../Sofa/Core/Binding_BaseClass.cpp | 48 +++++++++++++++++++ .../SofaPython3/Sofa/Core/Binding_BaseClass.h | 32 +++++++++++++ .../Sofa/Core/Binding_BaseClass_doc.h | 31 ++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.cpp create mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.h create mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass_doc.h diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.cpp new file mode 100644 index 00000000..7fbbc0dd --- /dev/null +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.cpp @@ -0,0 +1,48 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2021 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see <http://www.gnu.org/licenses/>. * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ + +#include <SofaPython3/Sofa/Core/Binding_BaseClass.h> +#include <SofaPython3/Sofa/Core/Binding_BaseClass_doc.h> +#include <sofa/core/objectmodel/BaseClass.h> + +namespace sofapython3 +{ +using namespace sofa::core::objectmodel; + +/// Makes an alias for the pybind11 namespace to increase readability. +namespace py { using namespace pybind11; } + +auto getBaseClassBinding(py::module& m) +{ + static py::class_<BaseClass, std::unique_ptr<BaseClass, py::nodelete>> base(m, "BaseClass", doc::baseclass::classdocstring); + return base; +} + +void moduleForwardAddBaseClass(py::module& m) +{ + getBaseClassBinding(m); +} + +void moduleAddBaseClass(py::module &m) +{ + // adds here the BaseClass's binded function (if any). +} + +} /// namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.h new file mode 100644 index 00000000..6ae2c6b7 --- /dev/null +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.h @@ -0,0 +1,32 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2021 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see <http://www.gnu.org/licenses/>. * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ + +#pragma once + +#include <pybind11/pybind11.h> + +namespace sofapython3 { + +/// Forward declaration in pybind11. +/// more details in: https://github.com/sofa-framework/SofaPython3/pull/457 +void moduleForwardAddBaseClass(pybind11::module& m); +void moduleAddBaseClass(pybind11::module& m); + +} /// namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass_doc.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass_doc.h new file mode 100644 index 00000000..2ed3d7d3 --- /dev/null +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass_doc.h @@ -0,0 +1,31 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2021 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see <http://www.gnu.org/licenses/>. * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ + +#pragma once + +namespace sofapython3::doc::baseclass { + +static auto classdocstring = + R"(Class hierarchy reflection base class +This class provides information on the class and parent classes of components. +It is created by using the SOFA_CLASS macro on each new class declaration. +All classes deriving from Base should use the SOFA_CLASS macro within their declaration.)"; + +} From 423ba9e94d9b5d5bf4f1c237c0369bf1549dfe90 Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Thu, 17 Oct 2024 11:30:52 +0200 Subject: [PATCH 16/20] Add binding for BaseClass It should be completed if ones want more feature than just class declaration --- .../Sofa/Core/Binding_BaseClass.cpp | 48 +++++++++++++++++++ .../SofaPython3/Sofa/Core/Binding_BaseClass.h | 32 +++++++++++++ .../Sofa/Core/Binding_BaseClass_doc.h | 31 ++++++++++++ 3 files changed, 111 insertions(+) create mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.cpp create mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.h create mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass_doc.h diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.cpp new file mode 100644 index 00000000..7fbbc0dd --- /dev/null +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.cpp @@ -0,0 +1,48 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2021 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see <http://www.gnu.org/licenses/>. * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ + +#include <SofaPython3/Sofa/Core/Binding_BaseClass.h> +#include <SofaPython3/Sofa/Core/Binding_BaseClass_doc.h> +#include <sofa/core/objectmodel/BaseClass.h> + +namespace sofapython3 +{ +using namespace sofa::core::objectmodel; + +/// Makes an alias for the pybind11 namespace to increase readability. +namespace py { using namespace pybind11; } + +auto getBaseClassBinding(py::module& m) +{ + static py::class_<BaseClass, std::unique_ptr<BaseClass, py::nodelete>> base(m, "BaseClass", doc::baseclass::classdocstring); + return base; +} + +void moduleForwardAddBaseClass(py::module& m) +{ + getBaseClassBinding(m); +} + +void moduleAddBaseClass(py::module &m) +{ + // adds here the BaseClass's binded function (if any). +} + +} /// namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.h new file mode 100644 index 00000000..6ae2c6b7 --- /dev/null +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.h @@ -0,0 +1,32 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2021 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see <http://www.gnu.org/licenses/>. * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ + +#pragma once + +#include <pybind11/pybind11.h> + +namespace sofapython3 { + +/// Forward declaration in pybind11. +/// more details in: https://github.com/sofa-framework/SofaPython3/pull/457 +void moduleForwardAddBaseClass(pybind11::module& m); +void moduleAddBaseClass(pybind11::module& m); + +} /// namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass_doc.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass_doc.h new file mode 100644 index 00000000..2ed3d7d3 --- /dev/null +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass_doc.h @@ -0,0 +1,31 @@ +/****************************************************************************** +* SOFA, Simulation Open-Framework Architecture * +* (c) 2021 INRIA, USTL, UJF, CNRS, MGH * +* * +* This program is free software; you can redistribute it and/or modify it * +* under the terms of the GNU Lesser General Public License as published by * +* the Free Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, but WITHOUT * +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * +* for more details. * +* * +* You should have received a copy of the GNU Lesser General Public License * +* along with this program. If not, see <http://www.gnu.org/licenses/>. * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ + +#pragma once + +namespace sofapython3::doc::baseclass { + +static auto classdocstring = + R"(Class hierarchy reflection base class +This class provides information on the class and parent classes of components. +It is created by using the SOFA_CLASS macro on each new class declaration. +All classes deriving from Base should use the SOFA_CLASS macro within their declaration.)"; + +} From 6b8f021ce4e9b7e5490e19f3d2a24b65c97d3e48 Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Thu, 17 Oct 2024 11:47:45 +0200 Subject: [PATCH 17/20] Generalize the pybind11 forward declaration of classes. --- .../SofaPython3/Sofa/Core/Binding_Base.cpp | 15 +++++++++--- .../src/SofaPython3/Sofa/Core/Binding_Base.h | 4 +++- .../Sofa/Core/Binding_BaseData.cpp | 2 -- .../SofaPython3/Sofa/Core/Binding_BaseData.h | 2 ++ .../SofaPython3/Sofa/Core/Binding_BaseLink.h | 2 ++ .../Sofa/Core/Binding_BaseMeshTopology.cpp | 16 ++++++++++++- .../Sofa/Core/Binding_BaseMeshTopology.h | 3 +++ .../Sofa/Core/Binding_BaseObject.cpp | 15 ++++++++++-- .../Sofa/Core/Binding_BaseObject.h | 2 ++ .../SofaPython3/Sofa/Core/Binding_Mass.cpp | 6 +++++ .../src/SofaPython3/Sofa/Core/Binding_Mass.h | 3 +++ .../Sofa/Core/Binding_Topology.cpp | 11 ++++++++- .../SofaPython3/Sofa/Core/Binding_Topology.h | 3 +++ .../src/SofaPython3/Sofa/Core/CMakeLists.txt | 5 +++- .../SofaPython3/Sofa/Core/Submodule_Core.cpp | 24 ++++++++++++++++++- 15 files changed, 101 insertions(+), 12 deletions(-) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp index 6aa8d763..81365ecf 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp @@ -449,12 +449,21 @@ py::object BindingBase::setDataValues(Base& self, py::kwargs kwargs) return py::none(); } +auto getBaseBinding(py::module& m) +{ + static py::class_<Base, py_shared_ptr<Base>> base(m, "Base", py::dynamic_attr(), doc::base::BaseClass); + return base; +} + +void moduleForwardAddBase(py::module& m) +{ + getBaseBinding(m); +} + void moduleAddBase(py::module &m) { - moduleForwardAddBaseData(m); - moduleForwardAddBaseLink(m); + auto base = getBaseBinding(m); - py::class_<Base, py_shared_ptr<Base>> base(m, "Base", py::dynamic_attr(), doc::base::BaseClass); /// set & get the name as string. The alternative is to access the data field using /// obj.name.value = "aName" base.def("getName", [](Base& b){ return b.getName(); }, sofapython3::doc::base::getName); diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.h index 670ce54b..06a98e59 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.h @@ -68,7 +68,9 @@ class BindingBase static std::string getLinkPath(sofa::core::objectmodel::Base& self); }; - +/// Forward declaration in pybind11. +/// more details in: https://github.com/sofa-framework/SofaPython3/pull/457 +void moduleForwardAddBase(pybind11::module& m); void moduleAddBase(pybind11::module& m); } /// namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp index ecc83750..d00341e6 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp @@ -207,8 +207,6 @@ void moduleForwardAddBaseData(py::module& m) void moduleAddBaseData(py::module& m) { /// Register the BaseData binding into the pybind11 system. - //py::class_<BaseData, std::unique_ptr<sofa::core::objectmodel::BaseData, pybind11::nodelete>> data(m, "Data", sofapython3::doc::baseData::BaseDataClass); - auto data =getPythonClassForBaseData(m); data.def("getName", [](BaseData& b){ return b.getName(); }, sofapython3::doc::baseData::getName); data.def("setName", [](BaseData& b, const std::string& s){ b.setName(s); }, sofapython3::doc::baseData::setName); diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h index badd6522..54be7010 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h @@ -24,6 +24,8 @@ namespace sofapython3 { + /// Forward declaration in pybind11. + /// more details in: https://github.com/sofa-framework/SofaPython3/pull/457 void moduleForwardAddBaseData(pybind11::module& m); void moduleAddBaseData(pybind11::module& m); diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h index 1cf5df4a..7beca2fa 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h @@ -24,6 +24,8 @@ namespace sofapython3 { + /// Forward declaration in pybind11. + /// more details in: https://github.com/sofa-framework/SofaPython3/pull/457 void moduleForwardAddBaseLink(pybind11::module& m); void moduleAddBaseLink(pybind11::module& m); diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.cpp index 2759c530..886179b0 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.cpp @@ -21,6 +21,7 @@ #include <SofaPython3/Sofa/Core/Binding_Base.h> #include <SofaPython3/Sofa/Core/Binding_BaseContext.h> +#include <SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h> #include <SofaPython3/PythonFactory.h> #include <sofa/core/BaseState.h> #include <sofa/core/objectmodel/BaseObject.h> @@ -36,8 +37,21 @@ using namespace sofa::core::topology; namespace sofapython3 { + +auto getPythonClassForBaseMeshTopology(py::module& m) +{ + /// Register the BaseData binding into the pybind11 system. + static py::class_<BaseMeshTopology, Topology, py_shared_ptr<BaseMeshTopology>> basemesh(m, "BaseMeshTopology"); + return basemesh; +} + +void moduleForwardAddBaseMeshTopology(py::module& m) +{ + getPythonClassForBaseMeshTopology(m); +} + void moduleAddBaseMeshTopology(py::module& m) { - py::class_<BaseMeshTopology, Topology, py_shared_ptr<BaseMeshTopology>> c (m, "BaseMeshTopology"); + auto c = getPythonClassForBaseMeshTopology(m); /// register the BaseMeshTopology binding in the downcasting subsystem PythonFactory::registerType<BaseMeshTopology>([](sofa::core::objectmodel::Base* object) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h index db28451e..7f8dd115 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h @@ -24,6 +24,9 @@ namespace sofapython3 { +/// Forward declaration in pybind11. +/// more details in: https://github.com/sofa-framework/SofaPython3/pull/457 +void moduleForwardAddBaseMeshTopology(pybind11::module &m); void moduleAddBaseMeshTopology(pybind11::module &m); } // namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.cpp index 7f9a476c..06fe77b6 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.cpp @@ -188,10 +188,21 @@ py::object __getitem__(BaseObject &self, std::string s) return getItem(self, s); } -void moduleAddBaseObject(py::module& m) +auto getBaseObjectBinding(py::module& m) { /// Register the BaseObject binding into the pybind11 typing system - py::class_<BaseObject, Base, py_shared_ptr<BaseObject>>p(m, "Object", sofapython3::doc::baseObject::Class); + static py::class_<BaseObject, Base, py_shared_ptr<BaseObject>>p(m, "Object", sofapython3::doc::baseObject::Class); + return p; +} + +void moduleForwardAddBaseObject(py::module& m) +{ + getBaseObjectBinding(m); +} + +void moduleAddBaseObject(py::module& m) +{ + auto p = getBaseObjectBinding(m); /// Register the BaseObject binding into the downcasting subsystem PythonFactory::registerType<sofa::core::objectmodel::BaseObject>( diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.h index 3e40176d..b85eed1f 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.h @@ -29,6 +29,8 @@ class BaseObject; namespace sofapython3 { pybind11::object getItem(const sofa::core::objectmodel::BaseObject & self, const std::string& path); + +void moduleForwardAddBaseObject(pybind11::module &m); void moduleAddBaseObject(pybind11::module &m); } /// namespace sofapython diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.cpp index 75af4211..268b7a0d 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.cpp @@ -94,4 +94,10 @@ void moduleAddMass(py::module &m) { declare_mass<sofa::defaulttype::Rigid2dTypes>(m); } +void moduleForwardAddBaseMass(py::module& m) +{ + static py::class_<sofa::core::behavior::BaseMass, + sofa::core::Base, py_shared_ptr<sofa::core::behavior::BaseMass>> basemass(m, "BaseMass"); +} + } // namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.h index 826b78da..7316b6ab 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.h @@ -24,6 +24,9 @@ namespace sofapython3 { +/// Forward declaration in pybind11. +/// more details in: https://github.com/sofa-framework/SofaPython3/pull/457 +void moduleForwardAddBaseMass(pybind11::module &m); void moduleAddMass(pybind11::module &m); } /// namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.cpp index ed57ba11..63c182c5 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.cpp @@ -35,8 +35,17 @@ using namespace sofa::core::topology; namespace sofapython3 { +auto getTopologyClass(py::module& m){ + static py::class_<Topology, BaseObject, py_shared_ptr<Topology>> c (m, "Topology"); + return c; +} + +void moduleForwardAddTopology(py::module& m) { + getTopologyClass(m); +} + void moduleAddTopology(py::module& m) { - py::class_<Topology, BaseObject, py_shared_ptr<Topology>> c (m, "Topology"); + getTopologyClass(m); } } // namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.h index 5f89f0e1..4bd7d4d1 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.h @@ -24,6 +24,9 @@ namespace sofapython3 { +/// Forward declaration in pybind11. +/// more details in: https://github.com/sofa-framework/SofaPython3/pull/457 +void moduleForwardAddTopology(pybind11::module &m); void moduleAddTopology(pybind11::module &m); } // namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt b/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt index 6dad5fea..d7ff4fd7 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt @@ -3,6 +3,8 @@ project(Bindings.Sofa.Core) set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Base.h ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Base_doc.h + ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseClass.h + ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseClass_doc.h ${CMAKE_CURRENT_SOURCE_DIR}/Binding_DataDict.h ${CMAKE_CURRENT_SOURCE_DIR}/Binding_DataDict_doc.h ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseData.h @@ -51,6 +53,7 @@ set(HEADER_FILES set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Base.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseClass.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseData.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_DataDict.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseObject.cpp @@ -72,12 +75,12 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Binding_NodeIterator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_PointSetTopologyModifier.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Prefab.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_Core.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_PythonScriptEvent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseLink.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Topology.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseMeshTopology.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_TaskScheduler.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_Core.cpp ) if (NOT TARGET SofaPython3::Plugin) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp index 546bb435..462d220c 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp @@ -23,6 +23,7 @@ using sofa::helper::logging::Message; #include <SofaPython3/Sofa/Core/Binding_Base.h> +#include <SofaPython3/Sofa/Core/Binding_BaseClass.h> #include <SofaPython3/Sofa/Core/Binding_BaseContext.h> #include <SofaPython3/Sofa/Core/Binding_BaseObject.h> #include <SofaPython3/Sofa/Core/Binding_DataDict.h> @@ -44,6 +45,7 @@ using sofa::helper::logging::Message; #include <SofaPython3/Sofa/Core/Binding_PythonScriptEvent.h> #include <SofaPython3/Sofa/Core/Binding_Topology.h> #include <SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h> +#include <SofaPython3/Sofa/Core/Binding_Topology.h> #include <SofaPython3/Sofa/Core/Binding_TaskScheduler.h> #include <SofaPython3/Sofa/Core/Data/Binding_DataString.h> @@ -103,6 +105,27 @@ PYBIND11_MODULE(Core, core) #Sofa.Core.WriteAccessor )doc"; + + + /// Forward declaration of a class in pybind11. + /// The general idea is that to avoid typeing errors in pybind11 because of -yet- to + /// define classes it is needed to register binded class before any use (including use + /// in function signature inferance) + /// more details in: https://github.com/sofa-framework/SofaPython3/pull/457 + moduleForwardAddBaseClass(core); + moduleForwardAddBase(core); + moduleForwardAddBaseObject(core); + moduleForwardAddBaseData(core); + moduleForwardAddBaseLink(core); + moduleForwardAddTopology(core); + moduleForwardAddBaseMeshTopology(core); + moduleForwardAddBaseMass(core); + + py::class_<sofa::core::behavior::BaseMechanicalState, + Base, py_shared_ptr<sofa::core::behavior::BaseMechanicalState>> basems(core, "BaseMechanicalState"); + + /// When all forward declarations in pybind11 are done we can actually fully + /// define the full binding. moduleAddPythonScriptEvent(); moduleAddDataDict(core); moduleAddDataDictIterator(core); @@ -143,7 +166,6 @@ PYBIND11_MODULE(Core, core) msg_info("SofaPython3.Core") << "Sofa.Core unload()"; })); - } } ///namespace sofapython3 From cbe250571774eddce3abee2f7f4448e9d4a9c3b3 Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Thu, 17 Oct 2024 11:48:13 +0200 Subject: [PATCH 18/20] Add pybind11 forward declaration to Node --- .../Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp | 11 ++++++----- .../Sofa/src/SofaPython3/Sofa/Core/Binding_Node.h | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp index af2907ff..f20275db 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp @@ -638,11 +638,12 @@ void moduleAddNode(py::module &m) { p.def("add", &addKwargs, sofapython3::doc::sofa::core::Node::addKwargs); def_method(p, "addObject") - .add_override("addObject(self, typename: str, **kwargs) -> Sofa.Core.Object", - addObjectKwargs, sofapython3::doc::sofa::core::Node::addObjectKwargs) - .add_override(addObject, sofapython3::doc::sofa::core::Node::addObject) - .add_override("addObject[T](self, type_: type, **kwargs) -> T", - addObjectGenericType, sofapython3::doc::sofa::core::Node::addObjectGenerictype); + .add_override("addObject(self, typename: str, **kwargs) -> Sofa.Core.Object", + addObjectKwargs, sofapython3::doc::sofa::core::Node::addObjectKwargs) + .add_override(addObject, + sofapython3::doc::sofa::core::Node::addObject, py::keep_alive<0, 2>()) + .add_override("addObject[T](self, python_type: type, **kwargs) -> T", + addObjectGenericType, sofapython3::doc::sofa::core::Node::addObjectGenerictype); p.def("createObject", &createObject, sofapython3::doc::sofa::core::Node::createObject, py::keep_alive<0, 2>()); p.def("hasObject", &hasObject, sofapython3::doc::sofa::core::Node::hasObject); diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.h index 9224ab1d..608eadbe 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.h @@ -23,6 +23,7 @@ namespace sofapython3 { +void moduleForwardAddNode(pybind11::module& m); void moduleAddNode(pybind11::module &m); } /// namespace sofapython3 From 2bd7ff65a05422f0d20a52ee838183d414741008 Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Thu, 17 Oct 2024 11:47:45 +0200 Subject: [PATCH 19/20] Generalize the pybind11 forward declaration of classes. --- .../SofaPython3/Sofa/Core/Binding_Base.cpp | 15 +++++++++--- .../src/SofaPython3/Sofa/Core/Binding_Base.h | 4 +++- .../Sofa/Core/Binding_BaseData.cpp | 2 -- .../SofaPython3/Sofa/Core/Binding_BaseData.h | 2 ++ .../SofaPython3/Sofa/Core/Binding_BaseLink.h | 2 ++ .../Sofa/Core/Binding_BaseMeshTopology.cpp | 16 ++++++++++++- .../Sofa/Core/Binding_BaseMeshTopology.h | 3 +++ .../Sofa/Core/Binding_BaseObject.cpp | 15 ++++++++++-- .../Sofa/Core/Binding_BaseObject.h | 2 ++ .../SofaPython3/Sofa/Core/Binding_Mass.cpp | 6 +++++ .../src/SofaPython3/Sofa/Core/Binding_Mass.h | 3 +++ .../Sofa/Core/Binding_Topology.cpp | 11 ++++++++- .../SofaPython3/Sofa/Core/Binding_Topology.h | 3 +++ .../src/SofaPython3/Sofa/Core/CMakeLists.txt | 5 +++- .../SofaPython3/Sofa/Core/Submodule_Core.cpp | 24 ++++++++++++++++++- 15 files changed, 101 insertions(+), 12 deletions(-) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp index 6aa8d763..81365ecf 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.cpp @@ -449,12 +449,21 @@ py::object BindingBase::setDataValues(Base& self, py::kwargs kwargs) return py::none(); } +auto getBaseBinding(py::module& m) +{ + static py::class_<Base, py_shared_ptr<Base>> base(m, "Base", py::dynamic_attr(), doc::base::BaseClass); + return base; +} + +void moduleForwardAddBase(py::module& m) +{ + getBaseBinding(m); +} + void moduleAddBase(py::module &m) { - moduleForwardAddBaseData(m); - moduleForwardAddBaseLink(m); + auto base = getBaseBinding(m); - py::class_<Base, py_shared_ptr<Base>> base(m, "Base", py::dynamic_attr(), doc::base::BaseClass); /// set & get the name as string. The alternative is to access the data field using /// obj.name.value = "aName" base.def("getName", [](Base& b){ return b.getName(); }, sofapython3::doc::base::getName); diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.h index 670ce54b..06a98e59 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Base.h @@ -68,7 +68,9 @@ class BindingBase static std::string getLinkPath(sofa::core::objectmodel::Base& self); }; - +/// Forward declaration in pybind11. +/// more details in: https://github.com/sofa-framework/SofaPython3/pull/457 +void moduleForwardAddBase(pybind11::module& m); void moduleAddBase(pybind11::module& m); } /// namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp index ecc83750..d00341e6 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.cpp @@ -207,8 +207,6 @@ void moduleForwardAddBaseData(py::module& m) void moduleAddBaseData(py::module& m) { /// Register the BaseData binding into the pybind11 system. - //py::class_<BaseData, std::unique_ptr<sofa::core::objectmodel::BaseData, pybind11::nodelete>> data(m, "Data", sofapython3::doc::baseData::BaseDataClass); - auto data =getPythonClassForBaseData(m); data.def("getName", [](BaseData& b){ return b.getName(); }, sofapython3::doc::baseData::getName); data.def("setName", [](BaseData& b, const std::string& s){ b.setName(s); }, sofapython3::doc::baseData::setName); diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h index badd6522..54be7010 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseData.h @@ -24,6 +24,8 @@ namespace sofapython3 { + /// Forward declaration in pybind11. + /// more details in: https://github.com/sofa-framework/SofaPython3/pull/457 void moduleForwardAddBaseData(pybind11::module& m); void moduleAddBaseData(pybind11::module& m); diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h index 1cf5df4a..7beca2fa 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseLink.h @@ -24,6 +24,8 @@ namespace sofapython3 { + /// Forward declaration in pybind11. + /// more details in: https://github.com/sofa-framework/SofaPython3/pull/457 void moduleForwardAddBaseLink(pybind11::module& m); void moduleAddBaseLink(pybind11::module& m); diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.cpp index 2759c530..886179b0 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.cpp @@ -21,6 +21,7 @@ #include <SofaPython3/Sofa/Core/Binding_Base.h> #include <SofaPython3/Sofa/Core/Binding_BaseContext.h> +#include <SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h> #include <SofaPython3/PythonFactory.h> #include <sofa/core/BaseState.h> #include <sofa/core/objectmodel/BaseObject.h> @@ -36,8 +37,21 @@ using namespace sofa::core::topology; namespace sofapython3 { + +auto getPythonClassForBaseMeshTopology(py::module& m) +{ + /// Register the BaseData binding into the pybind11 system. + static py::class_<BaseMeshTopology, Topology, py_shared_ptr<BaseMeshTopology>> basemesh(m, "BaseMeshTopology"); + return basemesh; +} + +void moduleForwardAddBaseMeshTopology(py::module& m) +{ + getPythonClassForBaseMeshTopology(m); +} + void moduleAddBaseMeshTopology(py::module& m) { - py::class_<BaseMeshTopology, Topology, py_shared_ptr<BaseMeshTopology>> c (m, "BaseMeshTopology"); + auto c = getPythonClassForBaseMeshTopology(m); /// register the BaseMeshTopology binding in the downcasting subsystem PythonFactory::registerType<BaseMeshTopology>([](sofa::core::objectmodel::Base* object) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h index db28451e..7f8dd115 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h @@ -24,6 +24,9 @@ namespace sofapython3 { +/// Forward declaration in pybind11. +/// more details in: https://github.com/sofa-framework/SofaPython3/pull/457 +void moduleForwardAddBaseMeshTopology(pybind11::module &m); void moduleAddBaseMeshTopology(pybind11::module &m); } // namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.cpp index 7f9a476c..06fe77b6 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.cpp @@ -188,10 +188,21 @@ py::object __getitem__(BaseObject &self, std::string s) return getItem(self, s); } -void moduleAddBaseObject(py::module& m) +auto getBaseObjectBinding(py::module& m) { /// Register the BaseObject binding into the pybind11 typing system - py::class_<BaseObject, Base, py_shared_ptr<BaseObject>>p(m, "Object", sofapython3::doc::baseObject::Class); + static py::class_<BaseObject, Base, py_shared_ptr<BaseObject>>p(m, "Object", sofapython3::doc::baseObject::Class); + return p; +} + +void moduleForwardAddBaseObject(py::module& m) +{ + getBaseObjectBinding(m); +} + +void moduleAddBaseObject(py::module& m) +{ + auto p = getBaseObjectBinding(m); /// Register the BaseObject binding into the downcasting subsystem PythonFactory::registerType<sofa::core::objectmodel::BaseObject>( diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.h index 3e40176d..b85eed1f 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseObject.h @@ -29,6 +29,8 @@ class BaseObject; namespace sofapython3 { pybind11::object getItem(const sofa::core::objectmodel::BaseObject & self, const std::string& path); + +void moduleForwardAddBaseObject(pybind11::module &m); void moduleAddBaseObject(pybind11::module &m); } /// namespace sofapython diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.cpp index 75af4211..268b7a0d 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.cpp @@ -94,4 +94,10 @@ void moduleAddMass(py::module &m) { declare_mass<sofa::defaulttype::Rigid2dTypes>(m); } +void moduleForwardAddBaseMass(py::module& m) +{ + static py::class_<sofa::core::behavior::BaseMass, + sofa::core::Base, py_shared_ptr<sofa::core::behavior::BaseMass>> basemass(m, "BaseMass"); +} + } // namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.h index 826b78da..7316b6ab 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Mass.h @@ -24,6 +24,9 @@ namespace sofapython3 { +/// Forward declaration in pybind11. +/// more details in: https://github.com/sofa-framework/SofaPython3/pull/457 +void moduleForwardAddBaseMass(pybind11::module &m); void moduleAddMass(pybind11::module &m); } /// namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.cpp index ed57ba11..63c182c5 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.cpp @@ -35,8 +35,17 @@ using namespace sofa::core::topology; namespace sofapython3 { +auto getTopologyClass(py::module& m){ + static py::class_<Topology, BaseObject, py_shared_ptr<Topology>> c (m, "Topology"); + return c; +} + +void moduleForwardAddTopology(py::module& m) { + getTopologyClass(m); +} + void moduleAddTopology(py::module& m) { - py::class_<Topology, BaseObject, py_shared_ptr<Topology>> c (m, "Topology"); + getTopologyClass(m); } } // namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.h b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.h index 5f89f0e1..4bd7d4d1 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Topology.h @@ -24,6 +24,9 @@ namespace sofapython3 { +/// Forward declaration in pybind11. +/// more details in: https://github.com/sofa-framework/SofaPython3/pull/457 +void moduleForwardAddTopology(pybind11::module &m); void moduleAddTopology(pybind11::module &m); } // namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt b/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt index 6dad5fea..d7ff4fd7 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt @@ -3,6 +3,8 @@ project(Bindings.Sofa.Core) set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Base.h ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Base_doc.h + ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseClass.h + ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseClass_doc.h ${CMAKE_CURRENT_SOURCE_DIR}/Binding_DataDict.h ${CMAKE_CURRENT_SOURCE_DIR}/Binding_DataDict_doc.h ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseData.h @@ -51,6 +53,7 @@ set(HEADER_FILES set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Base.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseClass.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseData.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_DataDict.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseObject.cpp @@ -72,12 +75,12 @@ set(SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Binding_NodeIterator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_PointSetTopologyModifier.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Prefab.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_Core.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_PythonScriptEvent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseLink.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_Topology.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_BaseMeshTopology.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Binding_TaskScheduler.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_Core.cpp ) if (NOT TARGET SofaPython3::Plugin) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp index 546bb435..462d220c 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Submodule_Core.cpp @@ -23,6 +23,7 @@ using sofa::helper::logging::Message; #include <SofaPython3/Sofa/Core/Binding_Base.h> +#include <SofaPython3/Sofa/Core/Binding_BaseClass.h> #include <SofaPython3/Sofa/Core/Binding_BaseContext.h> #include <SofaPython3/Sofa/Core/Binding_BaseObject.h> #include <SofaPython3/Sofa/Core/Binding_DataDict.h> @@ -44,6 +45,7 @@ using sofa::helper::logging::Message; #include <SofaPython3/Sofa/Core/Binding_PythonScriptEvent.h> #include <SofaPython3/Sofa/Core/Binding_Topology.h> #include <SofaPython3/Sofa/Core/Binding_BaseMeshTopology.h> +#include <SofaPython3/Sofa/Core/Binding_Topology.h> #include <SofaPython3/Sofa/Core/Binding_TaskScheduler.h> #include <SofaPython3/Sofa/Core/Data/Binding_DataString.h> @@ -103,6 +105,27 @@ PYBIND11_MODULE(Core, core) #Sofa.Core.WriteAccessor )doc"; + + + /// Forward declaration of a class in pybind11. + /// The general idea is that to avoid typeing errors in pybind11 because of -yet- to + /// define classes it is needed to register binded class before any use (including use + /// in function signature inferance) + /// more details in: https://github.com/sofa-framework/SofaPython3/pull/457 + moduleForwardAddBaseClass(core); + moduleForwardAddBase(core); + moduleForwardAddBaseObject(core); + moduleForwardAddBaseData(core); + moduleForwardAddBaseLink(core); + moduleForwardAddTopology(core); + moduleForwardAddBaseMeshTopology(core); + moduleForwardAddBaseMass(core); + + py::class_<sofa::core::behavior::BaseMechanicalState, + Base, py_shared_ptr<sofa::core::behavior::BaseMechanicalState>> basems(core, "BaseMechanicalState"); + + /// When all forward declarations in pybind11 are done we can actually fully + /// define the full binding. moduleAddPythonScriptEvent(); moduleAddDataDict(core); moduleAddDataDictIterator(core); @@ -143,7 +166,6 @@ PYBIND11_MODULE(Core, core) msg_info("SofaPython3.Core") << "Sofa.Core unload()"; })); - } } ///namespace sofapython3 From 56c541ff1b8895267422122fcead6443c5785541 Mon Sep 17 00:00:00 2001 From: Damien Marchal <damien.marchal@univ-lille1.fr> Date: Sat, 9 Nov 2024 00:10:48 +0100 Subject: [PATCH 20/20] FIXUP --- .../Sofa/Types/Binding_CompressedRowSparseMatrix.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Types/Binding_CompressedRowSparseMatrix.h b/bindings/Sofa/src/SofaPython3/Sofa/Types/Binding_CompressedRowSparseMatrix.h index 5ff99c44..13eeb571 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Types/Binding_CompressedRowSparseMatrix.h +++ b/bindings/Sofa/src/SofaPython3/Sofa/Types/Binding_CompressedRowSparseMatrix.h @@ -24,15 +24,6 @@ namespace sofapython3 { -<<<<<<<< HEAD:bindings/Sofa/src/SofaPython3/Sofa/Types/Binding_CompressedRowSparseMatrix.h void moduleAddCompressedRowSparseMatrix(pybind11::module& m); } // namespace sofapython3 -======== -/// Forward declaration in pybind11. -/// more details in: https://github.com/sofa-framework/SofaPython3/pull/457 -void moduleForwardAddBaseClass(pybind11::module& m); -void moduleAddBaseClass(pybind11::module& m); - -} /// namespace sofapython3 ->>>>>>>> xp-component-stubgen:bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_BaseClass.h