From 3fd97b21080e0c3c806dac372025ad47e4e9b6af Mon Sep 17 00:00:00 2001 From: Damien Marchal Date: Fri, 10 Sep 2021 11:47:21 +0200 Subject: [PATCH 1/9] [SofaPython3] Call init() by default when creating a python object. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The default behavior should be the most common use case while more rare scenario should be accessible through explicit call. Currently the default case is: m = r.addObject("MechanicalObject", position=[1,2,3]) m.init() l.rest_position() ## Rest position is created from position at init This is a bit weird as one may expect that once "created" in python the object is immediately accessible in an inited state (not doing so imply user to call init() at every lines). After the PR the default case become: m = r.addObject("MechanicalObject", position=[1,2,3]) l.rest_position() But for rare use case where it makes sense the no init behavior can be done like that: m = r.addObject("MechanicalObject", position=[1,2,3], doNoInit=True) l.rest_position() # Rest position is "uninited" m.init() # You can control when you init the object l.rest_position() # Unit tests are provided to validate the behavior. --- .../src/SofaPython3/Sofa/Core/Binding_Node.cpp | 11 ++++++++++- bindings/Sofa/tests/Simulation/Node.py | 15 +++++++++++---- 2 files changed, 21 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 5ea0cd51..36c70080 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp @@ -18,7 +18,6 @@ * Contact information: contact@sofa-framework.org * ******************************************************************************/ - /// Neede to have automatic conversion from pybind types to stl container. #include @@ -170,12 +169,18 @@ py::object hasObject(Node &n, const std::string &name) /// Implement the addObject function. py::object addObjectKwargs(Node* self, const std::string& type, const py::kwargs& kwargs) { + bool doInit = true; if (kwargs.contains("name")) { std::string name = py::str(kwargs["name"]); if (sofapython3::isProtectedKeyword(name)) throw py::value_error("addObject: Cannot call addObject with name " + name + ": Protected keyword"); } + if (kwargs.contains("__noInit")) + { + doInit = !py::bool_(kwargs["__noInit"]); + kwargs.attr("pop")("__noInit"); + } /// Prepare the description to hold the different python attributes as data field's /// arguments then create the object. BaseObjectDescription desc {type.c_str(), type.c_str()}; @@ -210,6 +215,10 @@ py::object addObjectKwargs(Node* self, const std::string& type, const py::kwargs if(d) d->setPersistent(true); } + if(doInit) + { + object->init(); + } return PythonFactory::toPython(object.get()); } diff --git a/bindings/Sofa/tests/Simulation/Node.py b/bindings/Sofa/tests/Simulation/Node.py index cb9f0df7..62246698 100644 --- a/bindings/Sofa/tests/Simulation/Node.py +++ b/bindings/Sofa/tests/Simulation/Node.py @@ -42,14 +42,21 @@ def test_GetAttr(self): self.assertTrue(o is not None) self.assertTrue(root.child1.mechanical is not None) - def test_init(self): + def test_addObject_noInit(self): + root = Sofa.Core.Node("rootNode") + root.addObject("RequiredPlugin", name="SofaBaseMechanics") + c = root.addChild("child1") + c = c.addObject("MechanicalObject", name="MO", position=[0.0,1.0,2.0]*100, __noInit=True) + self.assertEqual(len(c.rest_position.value), 0) + c.init() + self.assertEqual(len(c.rest_position.value), 100) + + def test_addObject_defaultInit(self): root = Sofa.Core.Node("rootNode") root.addObject("RequiredPlugin", name="SofaBaseMechanics") c = root.addChild("child1") c = c.addObject("MechanicalObject", name="MO", position=[0.0,1.0,2.0]*100) - root.init() - print("TYPE: "+str(len(c.position.value))) - self.assertEqual(len(c.position.value), 100) + self.assertEqual(len(c.rest_position.value), 100) def test_createObjectInvalid(self): root = Sofa.Core.Node("rootNode") From bca1050d4409846a2d837942bc77aec99d05743e Mon Sep 17 00:00:00 2001 From: Damien Marchal Date: Wed, 15 Sep 2021 13:33:37 +0200 Subject: [PATCH 2/9] [Bindings/Sofa] Add Sofa.__futurefeatures__ To control if users want to activate news features in the binding. --- bindings/Sofa/package/__futurefeatures__.py | 3 +++ bindings/Sofa/package/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 bindings/Sofa/package/__futurefeatures__.py diff --git a/bindings/Sofa/package/__futurefeatures__.py b/bindings/Sofa/package/__futurefeatures__.py new file mode 100644 index 00000000..998301b1 --- /dev/null +++ b/bindings/Sofa/package/__futurefeatures__.py @@ -0,0 +1,3 @@ +import Sofa + + diff --git a/bindings/Sofa/package/__init__.py b/bindings/Sofa/package/__init__.py index 30bafb2d..8e2305c1 100644 --- a/bindings/Sofa/package/__init__.py +++ b/bindings/Sofa/package/__init__.py @@ -44,7 +44,7 @@ from .prefab import * -__all__=["constants", "Helper", "Core", "Simulation", "Types", "SofaTypes", "prefab"] +__all__=["constants", "Helper", "Core", "Simulation", "Types", "SofaTypes", "prefab", "__futurefeatures__"] # Keep a list of the modules always imported in the Sofa-PythonEnvironment try: From df6792b1f2b9d3064f580cd08d35ec7ae1a43159 Mon Sep 17 00:00:00 2001 From: Damien Marchal Date: Wed, 15 Sep 2021 20:12:27 +0200 Subject: [PATCH 3/9] [SofaPython3/Config] Add a mechanism to activate/deactivate futurefeatures. The mechanisme is composed of three parts: - SofaPython3::Config (the c++ part) - SofaPython3::Binding::Config (the python binding) Activating an existing futurefeature: ------------------------------------- ```python import SofaPython3.__futurefeatures__ SofaPython3.__futurefeatures__.object_auto_init = True # To activate the auto init feature. ``` Adding a new futurefeature: --------------------------- In binding/Sofa/package/__futurefeatures__.py, add you feature at the end of the FeatureSet::__init__ constructor. In your c++ code you can test if the feature is activated by doing ```c++ #include if( sofapython3::config::futurefeatures::get("myFeature") ) .... ``` In your python code you can test if the feature is activated by doing ```python import Sofa.__futurefeatures__ if Sofa.__futurefeatures__.myFeature: print("The feature is activated") ``` Signed-off-by: Damien Marchal --- CMakeLists.txt | 1 + Config/CMakeLists.txt | 27 ++++++++ Config/ConfigConfig.cmake.in | 22 +++++++ .../src/SofaPython3/Config/futurefeatures.cpp | 62 +++++++++++++++++++ .../src/SofaPython3/Config/futurefeatures.h | 43 +++++++++++++ bindings/Sofa/CMakeLists.txt | 1 + bindings/Sofa/package/__futurefeatures__.py | 21 ++++++- .../SofaPython3/Sofa/Config/CMakeLists.txt | 26 ++++++++ .../Sofa/Config/Submodule_Config.cpp | 46 ++++++++++++++ .../SofaPython3/Sofa/Core/Binding_Node.cpp | 16 ++--- .../src/SofaPython3/Sofa/Core/CMakeLists.txt | 2 +- 11 files changed, 258 insertions(+), 9 deletions(-) create mode 100644 Config/CMakeLists.txt create mode 100644 Config/ConfigConfig.cmake.in create mode 100644 Config/src/SofaPython3/Config/futurefeatures.cpp create mode 100644 Config/src/SofaPython3/Config/futurefeatures.h create mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Config/CMakeLists.txt create mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Config/Submodule_Config.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d04ddcec..f4723b38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,6 +171,7 @@ if (NOT SP3_COMPILED_AS_SUBPROJECT) message(STATUS "SOFA Framework:\n\tVersion: ${SofaFramework_VERSION}\n\tLocation: ${SOFA_ROOT_DIR}") endif() +add_subdirectory(Config) add_subdirectory(Plugin) add_subdirectory(bindings) add_subdirectory(examples) diff --git a/Config/CMakeLists.txt b/Config/CMakeLists.txt new file mode 100644 index 00000000..dda7c991 --- /dev/null +++ b/Config/CMakeLists.txt @@ -0,0 +1,27 @@ +project(Config VERSION 1.0) + +set(HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Config/futurefeatures.h +) + +set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Config/futurefeatures.cpp +) + +find_package(SofaFramework REQUIRED) + +add_library(${PROJECT_NAME} SHARED ${HEADER_FILES} ${SOURCE_FILES}) +add_library(SofaPython3::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PUBLIC SofaCore) + +sofa_create_component_in_package_with_targets( + COMPONENT_NAME ${PROJECT_NAME} + COMPONENT_VERSION ${SofaPython3_VERSION} + PACKAGE_NAME SofaPython3 + TARGETS ${PROJECT_NAME} AUTO_SET_TARGET_PROPERTIES + INCLUDE_SOURCE_DIR "src" + INCLUDE_INSTALL_DIR "." + OPTIMIZE_BUILD_DIR FALSE + RELOCATABLE ".." + ) diff --git a/Config/ConfigConfig.cmake.in b/Config/ConfigConfig.cmake.in new file mode 100644 index 00000000..0641dc00 --- /dev/null +++ b/Config/ConfigConfig.cmake.in @@ -0,0 +1,22 @@ +# CMake package configuration file for the @PROJECT_NAME@ module +@PACKAGE_GUARD@ +@PACKAGE_INIT@ + +set(SP3_BUILD_TEST @SP3_BUILD_TEST@) + +find_package(pybind11 CONFIG REQUIRED) +find_package(SofaFramework REQUIRED) +find_package(SofaSimulationGraph REQUIRED) + +if(SP3_BUILD_TEST) + find_package(Sofa.Testing REQUIRED) +endif() + +# If we are importing this config file and the target is not yet there this is indicating that +# target is an imported one. So we include it +if(NOT TARGET @PROJECT_NAME@) + include("${CMAKE_CURRENT_LIST_DIR}/PluginTargets.cmake") +endif() + +# Check that the component/target is there. +check_required_components(@PROJECT_NAME@) diff --git a/Config/src/SofaPython3/Config/futurefeatures.cpp b/Config/src/SofaPython3/Config/futurefeatures.cpp new file mode 100644 index 00000000..5dc972fa --- /dev/null +++ b/Config/src/SofaPython3/Config/futurefeatures.cpp @@ -0,0 +1,62 @@ +/****************************************************************************** +* 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 . * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#include +#include +#include +#include + +namespace sofapython3::config::futurefeatures +{ + +std::map features; + +bool get(const std::string& name) +{ + auto f = features.find(name); + if(f == features.end()) + throw std::runtime_error("Missing attribute '"+name+"'"); + + return (f->second); +} + +void set(const std::string& name, bool value) +{ + auto f = features.find(name); + if(f == features.end()) + throw std::runtime_error("Missing attribute '"+name+"'"); + + (f->second) = value; +} + +void init(const std::string& name, bool value) +{ + features[name] = value; +} + + +std::vector list_features() +{ + std::vector v; + for(auto& it : features) + v.push_back(it.first); + return v; +} + +} //namespace sofapython3::futurefeatures diff --git a/Config/src/SofaPython3/Config/futurefeatures.h b/Config/src/SofaPython3/Config/futurefeatures.h new file mode 100644 index 00000000..02c3a6fd --- /dev/null +++ b/Config/src/SofaPython3/Config/futurefeatures.h @@ -0,0 +1,43 @@ +/****************************************************************************** +* 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 . * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once + +#include +#include +#include + +namespace sofapython3::config::futurefeatures +{ + +/// Retrieve the value associated with the feature "name" +/// raise an exception if "name" is not existing. +SOFA_EXPORT_DYNAMIC_LIBRARY bool get(const std::string& name); + +/// Change the value associated with the feature "name" +/// raise an exception if "name" is not existing. +SOFA_EXPORT_DYNAMIC_LIBRARY void set(const std::string& name, bool value); + +/// Create and set a new value for feature with "name" +SOFA_EXPORT_DYNAMIC_LIBRARY void init(const std::string& name, bool value); + +/// Returns the list of registered features names +SOFA_EXPORT_DYNAMIC_LIBRARY std::vector list_features(); + +} ///namespace sofapython3::futurefeatures diff --git a/bindings/Sofa/CMakeLists.txt b/bindings/Sofa/CMakeLists.txt index 371c13d1..52cf6741 100644 --- a/bindings/Sofa/CMakeLists.txt +++ b/bindings/Sofa/CMakeLists.txt @@ -1,6 +1,7 @@ project(Bindings.Sofa) set(SOFABINDINGS_MODULE_LIST + Config Components Core Helper diff --git a/bindings/Sofa/package/__futurefeatures__.py b/bindings/Sofa/package/__futurefeatures__.py index 998301b1..ac7f38b2 100644 --- a/bindings/Sofa/package/__futurefeatures__.py +++ b/bindings/Sofa/package/__futurefeatures__.py @@ -1,3 +1,22 @@ -import Sofa +""" +Control which feature of the binding are activated +-------------------------------------------------- +""" +import Sofa.Config +import sys +class Foo: + def __init__(self): + Sofa.Config.init("object_auto_init", False) + def __setattr__(self, name, value): + Sofa.Config.set(name, value) + + def __getattr__(self, name): + return Sofa.Config.get(name) + + def __dir__(self): + return Sofa.Config.list_features() + +# Hack from Ruido von Rossum. +sys.modules[__name__] = Foo() diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Config/CMakeLists.txt b/bindings/Sofa/src/SofaPython3/Sofa/Config/CMakeLists.txt new file mode 100644 index 00000000..d22b0f75 --- /dev/null +++ b/bindings/Sofa/src/SofaPython3/Sofa/Config/CMakeLists.txt @@ -0,0 +1,26 @@ +project(Bindings.Sofa.Config) + +set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_Config.cpp + ) + +if (NOT TARGET SofaPython3::Plugin) + find_package(SofaPython3 REQUIRED) +endif() + +find_package(Sofa.Config REQUIRED) +find_package(SofaFramework REQUIRED) +find_package(SofaBaseCollision REQUIRED) +find_package(SofaBaseVisual REQUIRED) +find_package(SofaBaseUtils REQUIRED) + +SP3_add_python_module( + TARGET ${PROJECT_NAME} + PACKAGE Bindings + MODULE Config + DESTINATION Sofa + SOURCES ${SOURCE_FILES} + HEADERS ${HEADER_FILES} + DEPENDS Sofa.Config SofaBaseUtils SofaBaseCollision SofaCore SofaHelper SofaSimulationCore SofaDefaultType SofaBaseVisual SofaPython3::Config SofaPython3::Plugin +) + diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Config/Submodule_Config.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Config/Submodule_Config.cpp new file mode 100644 index 00000000..c8ad227f --- /dev/null +++ b/bindings/Sofa/src/SofaPython3/Sofa/Config/Submodule_Config.cpp @@ -0,0 +1,46 @@ +/****************************************************************************** +* 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 . * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ + +#include +#include +#include +#include +#include + +namespace py { using namespace pybind11; } + +namespace sofapython3 +{ + +/// The first parameter must be named the same as the module file to load. +PYBIND11_MODULE(Config, ffmodule) +{ + ffmodule.doc() = R"doc( + Control the the activation of new features + ------------------------------------------ + Sofa.Config.object_auto_init = True + )doc"; + ffmodule.def("init", sofapython3::config::futurefeatures::init); + ffmodule.def("set", sofapython3::config::futurefeatures::set); + ffmodule.def("get", sofapython3::config::futurefeatures::get); + ffmodule.def("list_features", sofapython3::config::futurefeatures::list_features); +} + +} ///namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp index 36c70080..1328a208 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/Binding_Node.cpp @@ -48,27 +48,28 @@ using sofapython3::PythonFactory; #include #include #include - using sofa::core::objectmodel::BaseObjectDescription; #include #include +#include + +#include + /// Makes an alias for the pybind11 namespace to increase readability. namespace py { using namespace pybind11; } - using sofa::simulation::Node; - -namespace sofapython3 { - +namespace sofapython3 +{ bool checkParamUsage(BaseObjectDescription& desc) { bool hasFailure = false; std::stringstream tmp; tmp <<"Unknown Attribute(s): " << msgendl; - for( auto it : desc.getAttributeMap() ) + for( auto& it : desc.getAttributeMap() ) { if (!it.second.isAccessed()) { @@ -215,7 +216,8 @@ py::object addObjectKwargs(Node* self, const std::string& type, const py::kwargs if(d) d->setPersistent(true); } - if(doInit) + + if(doInit && sofapython3::config::futurefeatures::get("object_auto_init")) { object->init(); } diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt b/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt index 14b41b24..c41c90f6 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt @@ -85,5 +85,5 @@ SP3_add_python_module( DESTINATION Sofa SOURCES ${SOURCE_FILES} HEADERS ${HEADER_FILES} - DEPENDS SofaBaseUtils SofaBaseCollision SofaCore SofaHelper SofaSimulationCore SofaDefaultType SofaBaseVisual SofaPython3::Plugin + DEPENDS SofaBaseUtils SofaBaseCollision SofaCore SofaHelper SofaSimulationCore SofaDefaultType SofaBaseVisual SofaPython3::Config SofaPython3::Plugin ) From aa8f506ff23879a97a338741aaacbff9ecffd578 Mon Sep 17 00:00:00 2001 From: Damien Marchal Date: Wed, 15 Sep 2021 20:13:44 +0200 Subject: [PATCH 4/9] [SofaPython3/Plugin] Restore the reloading of plugins. At each scene load the loaded python modules should be cleaned so they can be reloaded. Signed-off-by: Damien Marchal --- Plugin/src/SofaPython3/PythonEnvironment.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Plugin/src/SofaPython3/PythonEnvironment.cpp b/Plugin/src/SofaPython3/PythonEnvironment.cpp index 4dc4c5d9..4cc32885 100644 --- a/Plugin/src/SofaPython3/PythonEnvironment.cpp +++ b/Plugin/src/SofaPython3/PythonEnvironment.cpp @@ -229,9 +229,8 @@ void PythonEnvironment::Init() addPythonModulePathsForPluginsByName("SofaPython3"); - py::module::import("SofaRuntime"); getStaticData()->m_sofamodule = py::module::import("Sofa"); - + PyRun_SimpleString("import SofaRuntime"); // python livecoding related PyRun_SimpleString("from Sofa.livecoding import onReimpAFile"); @@ -239,7 +238,7 @@ void PythonEnvironment::Init() // general sofa-python stuff // python modules are automatically reloaded at each scene loading - //setAutomaticModuleReload( true ); + setAutomaticModuleReload( true ); // Initialize pluginLibraryPath by reading PluginManager's map std::map& map = PluginManager::getInstance().getPluginMap(); From 13c7cbafa74ed9d65af9b0c466c75ce051c48903 Mon Sep 17 00:00:00 2001 From: Damien Marchal Date: Wed, 15 Sep 2021 23:42:40 +0200 Subject: [PATCH 5/9] [bindings/Sofa.Config] Refactor & add contextmanager for Sofa.future.__enable_future__ --- bindings/Sofa/package/__futurefeatures__.py | 22 ---------- bindings/Sofa/package/__init__.py | 6 +-- bindings/Sofa/package/future.py | 41 +++++++++++++++++++ bindings/Sofa/tests/CMakeLists.txt | 2 + bindings/Sofa/tests/Config/Config.py | 15 +++++++ .../Sofa/tests/PythonModule_Sofa_test.cpp | 1 + bindings/Sofa/tests/Simulation/Node.py | 35 +++++++++++----- 7 files changed, 86 insertions(+), 36 deletions(-) delete mode 100644 bindings/Sofa/package/__futurefeatures__.py create mode 100644 bindings/Sofa/package/future.py create mode 100644 bindings/Sofa/tests/Config/Config.py diff --git a/bindings/Sofa/package/__futurefeatures__.py b/bindings/Sofa/package/__futurefeatures__.py deleted file mode 100644 index ac7f38b2..00000000 --- a/bindings/Sofa/package/__futurefeatures__.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Control which feature of the binding are activated --------------------------------------------------- -""" -import Sofa.Config -import sys - -class Foo: - def __init__(self): - Sofa.Config.init("object_auto_init", False) - - def __setattr__(self, name, value): - Sofa.Config.set(name, value) - - def __getattr__(self, name): - return Sofa.Config.get(name) - - def __dir__(self): - return Sofa.Config.list_features() - -# Hack from Ruido von Rossum. -sys.modules[__name__] = Foo() diff --git a/bindings/Sofa/package/__init__.py b/bindings/Sofa/package/__init__.py index 8e2305c1..309f88ad 100644 --- a/bindings/Sofa/package/__init__.py +++ b/bindings/Sofa/package/__init__.py @@ -37,14 +37,15 @@ import Sofa.constants import Sofa.Helper import Sofa.Core +import Sofa.Config import Sofa.Simulation import Sofa.Types import Sofa.Components import SofaTypes - from .prefab import * +from .future import __enable_feature__ -__all__=["constants", "Helper", "Core", "Simulation", "Types", "SofaTypes", "prefab", "__futurefeatures__"] +__all__=["constants", "Helper", "Core", "Simulation", "Types", "SofaTypes", "prefab", "future"] # Keep a list of the modules always imported in the Sofa-PythonEnvironment try: @@ -56,7 +57,6 @@ # e.g. plugin's modules defined from c++ __SofaPythonEnvironment_modulesExcludedFromReload = [] - def unloadModules(): """ call this function to unload python modules and to force their reload (useful to take into account their eventual modifications since diff --git a/bindings/Sofa/package/future.py b/bindings/Sofa/package/future.py new file mode 100644 index 00000000..39c29822 --- /dev/null +++ b/bindings/Sofa/package/future.py @@ -0,0 +1,41 @@ +""" +Activate/deactive some feature of sofa python + +Use that to control how some part of the binding should behave. + +Usage: + from Sofa.future import __enable_feature__ + + with __enable_feature__("feature_name", True): + do_something() + + with __enable_feature__("feature_name", False): + do_something() +""" +import Sofa.Config +from contextlib import ContextDecorator + +### Initialize the feature set. +Sofa.Config.init("object_auto_init", False) + +def list_features(): + return Sofa.Config.list_features() + +class __enable_feature__(ContextDecorator): + @staticmethod + def list_features(): + return self.Config.list_feature() + + def __init__(self, name, value): + self.name=name + self.new_value=value + self.old_value=None + + def __enter__(self): + self.old_value=Sofa.Config.get(self.name) + Sofa.Config.set(self.name, self.new_value) + return self + + def __exit__(self, *exc): + Sofa.Config.set(self.name, self.old_value) + return False diff --git a/bindings/Sofa/tests/CMakeLists.txt b/bindings/Sofa/tests/CMakeLists.txt index 7f97f59b..2837fde5 100644 --- a/bindings/Sofa/tests/CMakeLists.txt +++ b/bindings/Sofa/tests/CMakeLists.txt @@ -11,6 +11,7 @@ set(SOURCE_FILES set(PYTHON_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Components/Components.py + ${CMAKE_CURRENT_SOURCE_DIR}/Config/Config.py ${CMAKE_CURRENT_SOURCE_DIR}/Core/BaseData.py ${CMAKE_CURRENT_SOURCE_DIR}/Core/Base.py ${CMAKE_CURRENT_SOURCE_DIR}/Core/BaseObject.py @@ -51,6 +52,7 @@ add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) set(DIR_BINDING_LIST Components + Config Core Helper Simulation diff --git a/bindings/Sofa/tests/Config/Config.py b/bindings/Sofa/tests/Config/Config.py new file mode 100644 index 00000000..c285b698 --- /dev/null +++ b/bindings/Sofa/tests/Config/Config.py @@ -0,0 +1,15 @@ +# coding: utf8 + +import Sofa.Config +from Sofa.future import __enable_feature__ +import unittest + +class Test(unittest.TestCase): + def test_init_feature(self): + Sofa.Config.init("new_feature", False) + self.assertFalse(Sofa.Config.get("new_feature"), False) + + with __enable_feature__("new_feature", True): + self.assertEquals(Sofa.Config.get("new_feature"), True) + + self.assertFalse(Sofa.Config.get("new_feature"), False) diff --git a/bindings/Sofa/tests/PythonModule_Sofa_test.cpp b/bindings/Sofa/tests/PythonModule_Sofa_test.cpp index f1ac8f41..dfd7f812 100644 --- a/bindings/Sofa/tests/PythonModule_Sofa_test.cpp +++ b/bindings/Sofa/tests/PythonModule_Sofa_test.cpp @@ -54,6 +54,7 @@ static struct PythonModule_Sofa_tests : public PythonTestExtractor PythonModule_Sofa_tests() { const std::string executable_directory = sofa::helper::Utils::getExecutableDirectory(); + addTestDirectory(executable_directory+"/Config", "Sofa_Config_"); addTestDirectory(executable_directory+"/Core", "Sofa_Core_"); addTestDirectory(executable_directory+"/Helper", "Sofa_Helper_"); addTestDirectory(executable_directory+"/Simulation", "Sofa_Simulation_"); diff --git a/bindings/Sofa/tests/Simulation/Node.py b/bindings/Sofa/tests/Simulation/Node.py index 62246698..ec2ab93a 100644 --- a/bindings/Sofa/tests/Simulation/Node.py +++ b/bindings/Sofa/tests/Simulation/Node.py @@ -4,6 +4,7 @@ import Sofa.Types import Sofa.Simulation import SofaRuntime +from Sofa.future import __enable_feature__ class MyController(Sofa.Core.Controller): """This is my custom controller @@ -42,21 +43,33 @@ def test_GetAttr(self): self.assertTrue(o is not None) self.assertTrue(root.child1.mechanical is not None) - def test_addObject_noInit(self): - root = Sofa.Core.Node("rootNode") - root.addObject("RequiredPlugin", name="SofaBaseMechanics") - c = root.addChild("child1") - c = c.addObject("MechanicalObject", name="MO", position=[0.0,1.0,2.0]*100, __noInit=True) - self.assertEqual(len(c.rest_position.value), 0) - c.init() - self.assertEqual(len(c.rest_position.value), 100) + def test_future_addObject_noInit(self): + """With __enable_feature__("object_auto_init") the MechanicalObject + does not sets its rest_position if __noInit it passed as an argument""" + with __enable_feature__("object_auto_init", True): + root = Sofa.Core.Node("rootNode") + root.addObject("RequiredPlugin", name="SofaBaseMechanics") + c = root.addObject("MechanicalObject", name="MO", position=[0.0,1.0,2.0]*100, __noInit=True) + self.assertEqual(len(c.rest_position.value), 0) + c.init() + self.assertEqual(len(c.rest_position.value), 100) + + def test_future_addObject_defaultInit(self): + """With __enable_feature__("object_auto_init") the MechanicalObject + does sets its its rest_position.""" + with Sofa.future.__enable_feature__("object_auto_init", True): + root = Sofa.Core.Node("rootNode") + root.addObject("RequiredPlugin", name="SofaBaseMechanics") + c = root.addObject("MechanicalObject", name="MO", position=[0.0,1.0,2.0]*100) + self.assertEqual(len(c.rest_position.value), 100) def test_addObject_defaultInit(self): + """Without __enable_feature__("object_auto_init") the MechanicalObject + does not sets its rest_position""" root = Sofa.Core.Node("rootNode") root.addObject("RequiredPlugin", name="SofaBaseMechanics") - c = root.addChild("child1") - c = c.addObject("MechanicalObject", name="MO", position=[0.0,1.0,2.0]*100) - self.assertEqual(len(c.rest_position.value), 100) + c = root.addObject("MechanicalObject", name="MO", position=[0.0,1.0,2.0]*100) + self.assertEqual(len(c.rest_position.value), 0) def test_createObjectInvalid(self): root = Sofa.Core.Node("rootNode") From e9db9fb4e967cbd50a28a4966f78c4101a8bc5f0 Mon Sep 17 00:00:00 2001 From: Damien Marchal Date: Wed, 15 Sep 2021 13:33:37 +0200 Subject: [PATCH 6/9] [Bindings/Sofa] Add Sofa.__futurefeatures__ To control if users want to activate news features in the binding. --- bindings/Sofa/package/__futurefeatures__.py | 3 +++ bindings/Sofa/package/__init__.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 bindings/Sofa/package/__futurefeatures__.py diff --git a/bindings/Sofa/package/__futurefeatures__.py b/bindings/Sofa/package/__futurefeatures__.py new file mode 100644 index 00000000..998301b1 --- /dev/null +++ b/bindings/Sofa/package/__futurefeatures__.py @@ -0,0 +1,3 @@ +import Sofa + + diff --git a/bindings/Sofa/package/__init__.py b/bindings/Sofa/package/__init__.py index 30bafb2d..8e2305c1 100644 --- a/bindings/Sofa/package/__init__.py +++ b/bindings/Sofa/package/__init__.py @@ -44,7 +44,7 @@ from .prefab import * -__all__=["constants", "Helper", "Core", "Simulation", "Types", "SofaTypes", "prefab"] +__all__=["constants", "Helper", "Core", "Simulation", "Types", "SofaTypes", "prefab", "__futurefeatures__"] # Keep a list of the modules always imported in the Sofa-PythonEnvironment try: From 57c2a30068a9ab2c6f12243d7703ee356e2f8074 Mon Sep 17 00:00:00 2001 From: Damien Marchal Date: Wed, 15 Sep 2021 20:12:27 +0200 Subject: [PATCH 7/9] [SofaPython3/Config] Add a mechanism to activate/deactivate futurefeatures. The mechanisme is composed of three parts: - SofaPython3::Config (the c++ part) - SofaPython3::Binding::Config (the python binding) Activating an existing futurefeature: ------------------------------------- ```python import SofaPython3.__futurefeatures__ SofaPython3.__futurefeatures__.object_auto_init = True # To activate the auto init feature. ``` Adding a new futurefeature: --------------------------- In binding/Sofa/package/__futurefeatures__.py, add you feature at the end of the FeatureSet::__init__ constructor. In your c++ code you can test if the feature is activated by doing ```c++ if( sofapython3::config::futurefeatures::get("myFeature") ) .... ``` In your python code you can test if the feature is activated by doing ```python import Sofa.__futurefeatures__ if Sofa.__futurefeatures__.myFeature: print("The feature is activated") ``` Signed-off-by: Damien Marchal --- CMakeLists.txt | 1 + Config/CMakeLists.txt | 27 ++++++++ Config/ConfigConfig.cmake.in | 22 +++++++ .../src/SofaPython3/Config/futurefeatures.cpp | 62 +++++++++++++++++++ .../src/SofaPython3/Config/futurefeatures.h | 43 +++++++++++++ bindings/Sofa/CMakeLists.txt | 1 + bindings/Sofa/package/__futurefeatures__.py | 3 - bindings/Sofa/package/__init__.py | 6 +- bindings/Sofa/package/future.py | 43 +++++++++++++ .../SofaPython3/Sofa/Config/CMakeLists.txt | 26 ++++++++ .../Sofa/Config/Submodule_Config.cpp | 46 ++++++++++++++ .../src/SofaPython3/Sofa/Core/CMakeLists.txt | 2 +- bindings/Sofa/tests/CMakeLists.txt | 2 + bindings/Sofa/tests/Config/Config.py | 15 +++++ .../Sofa/tests/PythonModule_Sofa_test.cpp | 1 + 15 files changed, 293 insertions(+), 7 deletions(-) create mode 100644 Config/CMakeLists.txt create mode 100644 Config/ConfigConfig.cmake.in create mode 100644 Config/src/SofaPython3/Config/futurefeatures.cpp create mode 100644 Config/src/SofaPython3/Config/futurefeatures.h delete mode 100644 bindings/Sofa/package/__futurefeatures__.py create mode 100644 bindings/Sofa/package/future.py create mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Config/CMakeLists.txt create mode 100644 bindings/Sofa/src/SofaPython3/Sofa/Config/Submodule_Config.cpp create mode 100644 bindings/Sofa/tests/Config/Config.py diff --git a/CMakeLists.txt b/CMakeLists.txt index d04ddcec..f4723b38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,6 +171,7 @@ if (NOT SP3_COMPILED_AS_SUBPROJECT) message(STATUS "SOFA Framework:\n\tVersion: ${SofaFramework_VERSION}\n\tLocation: ${SOFA_ROOT_DIR}") endif() +add_subdirectory(Config) add_subdirectory(Plugin) add_subdirectory(bindings) add_subdirectory(examples) diff --git a/Config/CMakeLists.txt b/Config/CMakeLists.txt new file mode 100644 index 00000000..dda7c991 --- /dev/null +++ b/Config/CMakeLists.txt @@ -0,0 +1,27 @@ +project(Config VERSION 1.0) + +set(HEADER_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Config/futurefeatures.h +) + +set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Config/futurefeatures.cpp +) + +find_package(SofaFramework REQUIRED) + +add_library(${PROJECT_NAME} SHARED ${HEADER_FILES} ${SOURCE_FILES}) +add_library(SofaPython3::${PROJECT_NAME} ALIAS ${PROJECT_NAME}) + +target_link_libraries(${PROJECT_NAME} PUBLIC SofaCore) + +sofa_create_component_in_package_with_targets( + COMPONENT_NAME ${PROJECT_NAME} + COMPONENT_VERSION ${SofaPython3_VERSION} + PACKAGE_NAME SofaPython3 + TARGETS ${PROJECT_NAME} AUTO_SET_TARGET_PROPERTIES + INCLUDE_SOURCE_DIR "src" + INCLUDE_INSTALL_DIR "." + OPTIMIZE_BUILD_DIR FALSE + RELOCATABLE ".." + ) diff --git a/Config/ConfigConfig.cmake.in b/Config/ConfigConfig.cmake.in new file mode 100644 index 00000000..0641dc00 --- /dev/null +++ b/Config/ConfigConfig.cmake.in @@ -0,0 +1,22 @@ +# CMake package configuration file for the @PROJECT_NAME@ module +@PACKAGE_GUARD@ +@PACKAGE_INIT@ + +set(SP3_BUILD_TEST @SP3_BUILD_TEST@) + +find_package(pybind11 CONFIG REQUIRED) +find_package(SofaFramework REQUIRED) +find_package(SofaSimulationGraph REQUIRED) + +if(SP3_BUILD_TEST) + find_package(Sofa.Testing REQUIRED) +endif() + +# If we are importing this config file and the target is not yet there this is indicating that +# target is an imported one. So we include it +if(NOT TARGET @PROJECT_NAME@) + include("${CMAKE_CURRENT_LIST_DIR}/PluginTargets.cmake") +endif() + +# Check that the component/target is there. +check_required_components(@PROJECT_NAME@) diff --git a/Config/src/SofaPython3/Config/futurefeatures.cpp b/Config/src/SofaPython3/Config/futurefeatures.cpp new file mode 100644 index 00000000..5dc972fa --- /dev/null +++ b/Config/src/SofaPython3/Config/futurefeatures.cpp @@ -0,0 +1,62 @@ +/****************************************************************************** +* 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 . * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#include +#include +#include +#include + +namespace sofapython3::config::futurefeatures +{ + +std::map features; + +bool get(const std::string& name) +{ + auto f = features.find(name); + if(f == features.end()) + throw std::runtime_error("Missing attribute '"+name+"'"); + + return (f->second); +} + +void set(const std::string& name, bool value) +{ + auto f = features.find(name); + if(f == features.end()) + throw std::runtime_error("Missing attribute '"+name+"'"); + + (f->second) = value; +} + +void init(const std::string& name, bool value) +{ + features[name] = value; +} + + +std::vector list_features() +{ + std::vector v; + for(auto& it : features) + v.push_back(it.first); + return v; +} + +} //namespace sofapython3::futurefeatures diff --git a/Config/src/SofaPython3/Config/futurefeatures.h b/Config/src/SofaPython3/Config/futurefeatures.h new file mode 100644 index 00000000..02c3a6fd --- /dev/null +++ b/Config/src/SofaPython3/Config/futurefeatures.h @@ -0,0 +1,43 @@ +/****************************************************************************** +* 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 . * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ +#pragma once + +#include +#include +#include + +namespace sofapython3::config::futurefeatures +{ + +/// Retrieve the value associated with the feature "name" +/// raise an exception if "name" is not existing. +SOFA_EXPORT_DYNAMIC_LIBRARY bool get(const std::string& name); + +/// Change the value associated with the feature "name" +/// raise an exception if "name" is not existing. +SOFA_EXPORT_DYNAMIC_LIBRARY void set(const std::string& name, bool value); + +/// Create and set a new value for feature with "name" +SOFA_EXPORT_DYNAMIC_LIBRARY void init(const std::string& name, bool value); + +/// Returns the list of registered features names +SOFA_EXPORT_DYNAMIC_LIBRARY std::vector list_features(); + +} ///namespace sofapython3::futurefeatures diff --git a/bindings/Sofa/CMakeLists.txt b/bindings/Sofa/CMakeLists.txt index 371c13d1..52cf6741 100644 --- a/bindings/Sofa/CMakeLists.txt +++ b/bindings/Sofa/CMakeLists.txt @@ -1,6 +1,7 @@ project(Bindings.Sofa) set(SOFABINDINGS_MODULE_LIST + Config Components Core Helper diff --git a/bindings/Sofa/package/__futurefeatures__.py b/bindings/Sofa/package/__futurefeatures__.py deleted file mode 100644 index 998301b1..00000000 --- a/bindings/Sofa/package/__futurefeatures__.py +++ /dev/null @@ -1,3 +0,0 @@ -import Sofa - - diff --git a/bindings/Sofa/package/__init__.py b/bindings/Sofa/package/__init__.py index 8e2305c1..309f88ad 100644 --- a/bindings/Sofa/package/__init__.py +++ b/bindings/Sofa/package/__init__.py @@ -37,14 +37,15 @@ import Sofa.constants import Sofa.Helper import Sofa.Core +import Sofa.Config import Sofa.Simulation import Sofa.Types import Sofa.Components import SofaTypes - from .prefab import * +from .future import __enable_feature__ -__all__=["constants", "Helper", "Core", "Simulation", "Types", "SofaTypes", "prefab", "__futurefeatures__"] +__all__=["constants", "Helper", "Core", "Simulation", "Types", "SofaTypes", "prefab", "future"] # Keep a list of the modules always imported in the Sofa-PythonEnvironment try: @@ -56,7 +57,6 @@ # e.g. plugin's modules defined from c++ __SofaPythonEnvironment_modulesExcludedFromReload = [] - def unloadModules(): """ call this function to unload python modules and to force their reload (useful to take into account their eventual modifications since diff --git a/bindings/Sofa/package/future.py b/bindings/Sofa/package/future.py new file mode 100644 index 00000000..36fea9a3 --- /dev/null +++ b/bindings/Sofa/package/future.py @@ -0,0 +1,43 @@ +""" +Activate/deactive some feature of sofa python + +Use that to control how some part of the binding should behave. + +Usage: + from Sofa.future import __enable_feature__ + + with __enable_feature__("feature_name", True): + do_something() + + with __enable_feature__("feature_name", False): + do_something() +""" +import Sofa.Config +from contextlib import ContextDecorator + +### Initialize the feature set. +Sofa.Config.init("object_auto_init", False) +# Add your own feature by un-commenting the following line +#Sofa.Config.init("my_feature", False) + +def list_features(): + return Sofa.Config.list_features() + +class __enable_feature__(ContextDecorator): + @staticmethod + def list_features(): + return self.Config.list_feature() + + def __init__(self, name, value): + self.name=name + self.new_value=value + self.old_value=None + + def __enter__(self): + self.old_value=Sofa.Config.get(self.name) + Sofa.Config.set(self.name, self.new_value) + return self + + def __exit__(self, *exc): + Sofa.Config.set(self.name, self.old_value) + return False diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Config/CMakeLists.txt b/bindings/Sofa/src/SofaPython3/Sofa/Config/CMakeLists.txt new file mode 100644 index 00000000..d22b0f75 --- /dev/null +++ b/bindings/Sofa/src/SofaPython3/Sofa/Config/CMakeLists.txt @@ -0,0 +1,26 @@ +project(Bindings.Sofa.Config) + +set(SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_Config.cpp + ) + +if (NOT TARGET SofaPython3::Plugin) + find_package(SofaPython3 REQUIRED) +endif() + +find_package(Sofa.Config REQUIRED) +find_package(SofaFramework REQUIRED) +find_package(SofaBaseCollision REQUIRED) +find_package(SofaBaseVisual REQUIRED) +find_package(SofaBaseUtils REQUIRED) + +SP3_add_python_module( + TARGET ${PROJECT_NAME} + PACKAGE Bindings + MODULE Config + DESTINATION Sofa + SOURCES ${SOURCE_FILES} + HEADERS ${HEADER_FILES} + DEPENDS Sofa.Config SofaBaseUtils SofaBaseCollision SofaCore SofaHelper SofaSimulationCore SofaDefaultType SofaBaseVisual SofaPython3::Config SofaPython3::Plugin +) + diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Config/Submodule_Config.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Config/Submodule_Config.cpp new file mode 100644 index 00000000..c8ad227f --- /dev/null +++ b/bindings/Sofa/src/SofaPython3/Sofa/Config/Submodule_Config.cpp @@ -0,0 +1,46 @@ +/****************************************************************************** +* 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 . * +******************************************************************************* +* Contact information: contact@sofa-framework.org * +******************************************************************************/ + +#include +#include +#include +#include +#include + +namespace py { using namespace pybind11; } + +namespace sofapython3 +{ + +/// The first parameter must be named the same as the module file to load. +PYBIND11_MODULE(Config, ffmodule) +{ + ffmodule.doc() = R"doc( + Control the the activation of new features + ------------------------------------------ + Sofa.Config.object_auto_init = True + )doc"; + ffmodule.def("init", sofapython3::config::futurefeatures::init); + ffmodule.def("set", sofapython3::config::futurefeatures::set); + ffmodule.def("get", sofapython3::config::futurefeatures::get); + ffmodule.def("list_features", sofapython3::config::futurefeatures::list_features); +} + +} ///namespace sofapython3 diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt b/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt index 14b41b24..c41c90f6 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt @@ -85,5 +85,5 @@ SP3_add_python_module( DESTINATION Sofa SOURCES ${SOURCE_FILES} HEADERS ${HEADER_FILES} - DEPENDS SofaBaseUtils SofaBaseCollision SofaCore SofaHelper SofaSimulationCore SofaDefaultType SofaBaseVisual SofaPython3::Plugin + DEPENDS SofaBaseUtils SofaBaseCollision SofaCore SofaHelper SofaSimulationCore SofaDefaultType SofaBaseVisual SofaPython3::Config SofaPython3::Plugin ) diff --git a/bindings/Sofa/tests/CMakeLists.txt b/bindings/Sofa/tests/CMakeLists.txt index 7f97f59b..2837fde5 100644 --- a/bindings/Sofa/tests/CMakeLists.txt +++ b/bindings/Sofa/tests/CMakeLists.txt @@ -11,6 +11,7 @@ set(SOURCE_FILES set(PYTHON_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Components/Components.py + ${CMAKE_CURRENT_SOURCE_DIR}/Config/Config.py ${CMAKE_CURRENT_SOURCE_DIR}/Core/BaseData.py ${CMAKE_CURRENT_SOURCE_DIR}/Core/Base.py ${CMAKE_CURRENT_SOURCE_DIR}/Core/BaseObject.py @@ -51,6 +52,7 @@ add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) set(DIR_BINDING_LIST Components + Config Core Helper Simulation diff --git a/bindings/Sofa/tests/Config/Config.py b/bindings/Sofa/tests/Config/Config.py new file mode 100644 index 00000000..c285b698 --- /dev/null +++ b/bindings/Sofa/tests/Config/Config.py @@ -0,0 +1,15 @@ +# coding: utf8 + +import Sofa.Config +from Sofa.future import __enable_feature__ +import unittest + +class Test(unittest.TestCase): + def test_init_feature(self): + Sofa.Config.init("new_feature", False) + self.assertFalse(Sofa.Config.get("new_feature"), False) + + with __enable_feature__("new_feature", True): + self.assertEquals(Sofa.Config.get("new_feature"), True) + + self.assertFalse(Sofa.Config.get("new_feature"), False) diff --git a/bindings/Sofa/tests/PythonModule_Sofa_test.cpp b/bindings/Sofa/tests/PythonModule_Sofa_test.cpp index f1ac8f41..dfd7f812 100644 --- a/bindings/Sofa/tests/PythonModule_Sofa_test.cpp +++ b/bindings/Sofa/tests/PythonModule_Sofa_test.cpp @@ -54,6 +54,7 @@ static struct PythonModule_Sofa_tests : public PythonTestExtractor PythonModule_Sofa_tests() { const std::string executable_directory = sofa::helper::Utils::getExecutableDirectory(); + addTestDirectory(executable_directory+"/Config", "Sofa_Config_"); addTestDirectory(executable_directory+"/Core", "Sofa_Core_"); addTestDirectory(executable_directory+"/Helper", "Sofa_Helper_"); addTestDirectory(executable_directory+"/Simulation", "Sofa_Simulation_"); From 09127873719d22c2ce58d22046fd412655a0bdb2 Mon Sep 17 00:00:00 2001 From: Damien Marchal Date: Thu, 16 Sep 2021 00:11:50 +0200 Subject: [PATCH 8/9] [Bindings/Sofa.Config] Add has_feature in future.py --- bindings/Sofa/package/future.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bindings/Sofa/package/future.py b/bindings/Sofa/package/future.py index 36fea9a3..5664c272 100644 --- a/bindings/Sofa/package/future.py +++ b/bindings/Sofa/package/future.py @@ -16,10 +16,12 @@ from contextlib import ContextDecorator ### Initialize the feature set. -Sofa.Config.init("object_auto_init", False) # Add your own feature by un-commenting the following line #Sofa.Config.init("my_feature", False) +def has_feature(name): + return Sofa.Config.get(name) + def list_features(): return Sofa.Config.list_features() From 2e994ae1dd6abfb6854169ac7760cebb095da650 Mon Sep 17 00:00:00 2001 From: Damien Marchal Date: Mon, 27 Sep 2021 11:51:03 +0200 Subject: [PATCH 9/9] [all] Rename the introduced feature Sofa.Config.future into Sofa.Lifetime.future To make that consistant with the "lifetime" namespace we already have in Sofa. --- CMakeLists.txt | 2 +- {Config => Lifetime}/CMakeLists.txt | 6 +++--- .../LifetimeConfig.cmake.in | 0 .../src/SofaPython3/lifetime/features.cpp | 4 ++-- .../src/SofaPython3/lifetime/features.h | 2 +- bindings/Sofa/CMakeLists.txt | 2 +- bindings/Sofa/package/__init__.py | 4 ++-- .../Sofa/package/{future.py => lifetime.py} | 20 +++++++++---------- .../src/SofaPython3/Sofa/Core/CMakeLists.txt | 2 +- .../Sofa/{Config => Lifetime}/CMakeLists.txt | 8 ++++---- .../Submodule_Lifetime.cpp} | 14 ++++++------- bindings/Sofa/tests/CMakeLists.txt | 4 ++-- bindings/Sofa/tests/Config/Config.py | 15 -------------- bindings/Sofa/tests/Lifetime/Lifetime.py | 15 ++++++++++++++ 14 files changed, 49 insertions(+), 49 deletions(-) rename {Config => Lifetime}/CMakeLists.txt (77%) rename Config/ConfigConfig.cmake.in => Lifetime/LifetimeConfig.cmake.in (100%) rename Config/src/SofaPython3/Config/futurefeatures.cpp => Lifetime/src/SofaPython3/lifetime/features.cpp (96%) rename Config/src/SofaPython3/Config/futurefeatures.h => Lifetime/src/SofaPython3/lifetime/features.h (97%) rename bindings/Sofa/package/{future.py => lifetime.py} (63%) rename bindings/Sofa/src/SofaPython3/Sofa/{Config => Lifetime}/CMakeLists.txt (79%) rename bindings/Sofa/src/SofaPython3/Sofa/{Config/Submodule_Config.cpp => Lifetime/Submodule_Lifetime.cpp} (82%) delete mode 100644 bindings/Sofa/tests/Config/Config.py create mode 100644 bindings/Sofa/tests/Lifetime/Lifetime.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 39053497..34b404ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,7 +171,7 @@ if (NOT SP3_COMPILED_AS_SUBPROJECT) message(STATUS "SOFA Framework:\n\tVersion: ${SofaFramework_VERSION}\n\tLocation: ${SOFA_ROOT_DIR}") endif() -add_subdirectory(Config) +add_subdirectory(Lifetime) add_subdirectory(Plugin) add_subdirectory(bindings) add_subdirectory(examples) diff --git a/Config/CMakeLists.txt b/Lifetime/CMakeLists.txt similarity index 77% rename from Config/CMakeLists.txt rename to Lifetime/CMakeLists.txt index dda7c991..a4f15266 100644 --- a/Config/CMakeLists.txt +++ b/Lifetime/CMakeLists.txt @@ -1,11 +1,11 @@ -project(Config VERSION 1.0) +project(Lifetime VERSION 1.0) set(HEADER_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Config/futurefeatures.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/lifetime/features.h ) set(SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/Config/futurefeatures.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/SofaPython3/lifetime/features.cpp ) find_package(SofaFramework REQUIRED) diff --git a/Config/ConfigConfig.cmake.in b/Lifetime/LifetimeConfig.cmake.in similarity index 100% rename from Config/ConfigConfig.cmake.in rename to Lifetime/LifetimeConfig.cmake.in diff --git a/Config/src/SofaPython3/Config/futurefeatures.cpp b/Lifetime/src/SofaPython3/lifetime/features.cpp similarity index 96% rename from Config/src/SofaPython3/Config/futurefeatures.cpp rename to Lifetime/src/SofaPython3/lifetime/features.cpp index 5dc972fa..7bd70792 100644 --- a/Config/src/SofaPython3/Config/futurefeatures.cpp +++ b/Lifetime/src/SofaPython3/lifetime/features.cpp @@ -20,9 +20,9 @@ #include #include #include -#include +#include -namespace sofapython3::config::futurefeatures +namespace sofapython3::lifetime::features { std::map features; diff --git a/Config/src/SofaPython3/Config/futurefeatures.h b/Lifetime/src/SofaPython3/lifetime/features.h similarity index 97% rename from Config/src/SofaPython3/Config/futurefeatures.h rename to Lifetime/src/SofaPython3/lifetime/features.h index 02c3a6fd..58fe89dd 100644 --- a/Config/src/SofaPython3/Config/futurefeatures.h +++ b/Lifetime/src/SofaPython3/lifetime/features.h @@ -23,7 +23,7 @@ #include #include -namespace sofapython3::config::futurefeatures +namespace sofapython3::lifetime::features { /// Retrieve the value associated with the feature "name" diff --git a/bindings/Sofa/CMakeLists.txt b/bindings/Sofa/CMakeLists.txt index 52cf6741..f733f632 100644 --- a/bindings/Sofa/CMakeLists.txt +++ b/bindings/Sofa/CMakeLists.txt @@ -1,7 +1,7 @@ project(Bindings.Sofa) set(SOFABINDINGS_MODULE_LIST - Config + Lifetime Components Core Helper diff --git a/bindings/Sofa/package/__init__.py b/bindings/Sofa/package/__init__.py index 01eb88ab..30fcacb9 100644 --- a/bindings/Sofa/package/__init__.py +++ b/bindings/Sofa/package/__init__.py @@ -37,13 +37,13 @@ import Sofa.constants import Sofa.Helper import Sofa.Core -import Sofa.Config +import Sofa.Lifetime import Sofa.Simulation import Sofa.Types import Sofa.Components import SofaTypes from .prefab import * -from .future import __enable_feature__ +from .lifetime import __feature__ __all__=["constants", "Helper", "Core", "Simulation", "Types", "SofaTypes", "prefab", "future"] diff --git a/bindings/Sofa/package/future.py b/bindings/Sofa/package/lifetime.py similarity index 63% rename from bindings/Sofa/package/future.py rename to bindings/Sofa/package/lifetime.py index 5664c272..b3b73bf1 100644 --- a/bindings/Sofa/package/future.py +++ b/bindings/Sofa/package/lifetime.py @@ -4,28 +4,28 @@ Use that to control how some part of the binding should behave. Usage: - from Sofa.future import __enable_feature__ + from Sofa.Lifetime import __feature__ - with __enable_feature__("feature_name", True): + with __feature__("feature_name", True): do_something() - with __enable_feature__("feature_name", False): + with __feature__("feature_name", False): do_something() """ -import Sofa.Config +import Sofa.Lifetime from contextlib import ContextDecorator ### Initialize the feature set. # Add your own feature by un-commenting the following line -#Sofa.Config.init("my_feature", False) +#Sofa.Lifetime.init("my_feature", False) def has_feature(name): - return Sofa.Config.get(name) + return Sofa.Lifetime.get(name) def list_features(): - return Sofa.Config.list_features() + return Sofa.Lifetime.list_features() -class __enable_feature__(ContextDecorator): +class __feature__(ContextDecorator): @staticmethod def list_features(): return self.Config.list_feature() @@ -37,9 +37,9 @@ def __init__(self, name, value): def __enter__(self): self.old_value=Sofa.Config.get(self.name) - Sofa.Config.set(self.name, self.new_value) + Sofa.Lifetime.set(self.name, self.new_value) return self def __exit__(self, *exc): - Sofa.Config.set(self.name, self.old_value) + Sofa.Lifetime.set(self.name, self.old_value) return False diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt b/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt index c41c90f6..d9b28887 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt +++ b/bindings/Sofa/src/SofaPython3/Sofa/Core/CMakeLists.txt @@ -85,5 +85,5 @@ SP3_add_python_module( DESTINATION Sofa SOURCES ${SOURCE_FILES} HEADERS ${HEADER_FILES} - DEPENDS SofaBaseUtils SofaBaseCollision SofaCore SofaHelper SofaSimulationCore SofaDefaultType SofaBaseVisual SofaPython3::Config SofaPython3::Plugin + DEPENDS SofaBaseUtils SofaBaseCollision SofaCore SofaHelper SofaSimulationCore SofaDefaultType SofaBaseVisual SofaPython3::Lifetime SofaPython3::Plugin ) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Config/CMakeLists.txt b/bindings/Sofa/src/SofaPython3/Sofa/Lifetime/CMakeLists.txt similarity index 79% rename from bindings/Sofa/src/SofaPython3/Sofa/Config/CMakeLists.txt rename to bindings/Sofa/src/SofaPython3/Sofa/Lifetime/CMakeLists.txt index d22b0f75..bba64cec 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Config/CMakeLists.txt +++ b/bindings/Sofa/src/SofaPython3/Sofa/Lifetime/CMakeLists.txt @@ -1,7 +1,7 @@ -project(Bindings.Sofa.Config) +project(Bindings.Sofa.Lifetime) set(SOURCE_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_Config.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Submodule_Lifetime.cpp ) if (NOT TARGET SofaPython3::Plugin) @@ -17,10 +17,10 @@ find_package(SofaBaseUtils REQUIRED) SP3_add_python_module( TARGET ${PROJECT_NAME} PACKAGE Bindings - MODULE Config + MODULE Lifetime DESTINATION Sofa SOURCES ${SOURCE_FILES} HEADERS ${HEADER_FILES} - DEPENDS Sofa.Config SofaBaseUtils SofaBaseCollision SofaCore SofaHelper SofaSimulationCore SofaDefaultType SofaBaseVisual SofaPython3::Config SofaPython3::Plugin + DEPENDS Sofa.Config SofaBaseUtils SofaBaseCollision SofaCore SofaHelper SofaSimulationCore SofaDefaultType SofaBaseVisual SofaPython3::Lifetime SofaPython3::Plugin ) diff --git a/bindings/Sofa/src/SofaPython3/Sofa/Config/Submodule_Config.cpp b/bindings/Sofa/src/SofaPython3/Sofa/Lifetime/Submodule_Lifetime.cpp similarity index 82% rename from bindings/Sofa/src/SofaPython3/Sofa/Config/Submodule_Config.cpp rename to bindings/Sofa/src/SofaPython3/Sofa/Lifetime/Submodule_Lifetime.cpp index c8ad227f..73093f0e 100644 --- a/bindings/Sofa/src/SofaPython3/Sofa/Config/Submodule_Config.cpp +++ b/bindings/Sofa/src/SofaPython3/Sofa/Lifetime/Submodule_Lifetime.cpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include namespace py { using namespace pybind11; } @@ -30,17 +30,17 @@ namespace sofapython3 { /// The first parameter must be named the same as the module file to load. -PYBIND11_MODULE(Config, ffmodule) +PYBIND11_MODULE(Lifetime, ffmodule) { ffmodule.doc() = R"doc( Control the the activation of new features ------------------------------------------ - Sofa.Config.object_auto_init = True + Sofa.Lifetime.object_auto_init = True )doc"; - ffmodule.def("init", sofapython3::config::futurefeatures::init); - ffmodule.def("set", sofapython3::config::futurefeatures::set); - ffmodule.def("get", sofapython3::config::futurefeatures::get); - ffmodule.def("list_features", sofapython3::config::futurefeatures::list_features); + ffmodule.def("init", sofapython3::lifetime::features::init); + ffmodule.def("set", sofapython3::lifetime::features::set); + ffmodule.def("get", sofapython3::lifetime::features::get); + ffmodule.def("list_features", sofapython3::lifetime::features::list_features); } } ///namespace sofapython3 diff --git a/bindings/Sofa/tests/CMakeLists.txt b/bindings/Sofa/tests/CMakeLists.txt index ad7cbc3f..a4013fe2 100644 --- a/bindings/Sofa/tests/CMakeLists.txt +++ b/bindings/Sofa/tests/CMakeLists.txt @@ -11,7 +11,7 @@ set(SOURCE_FILES set(PYTHON_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Components/Components.py - ${CMAKE_CURRENT_SOURCE_DIR}/Config/Config.py + ${CMAKE_CURRENT_SOURCE_DIR}/Lifetime/Lifetime.py ${CMAKE_CURRENT_SOURCE_DIR}/Core/BaseData.py ${CMAKE_CURRENT_SOURCE_DIR}/Core/Base.py ${CMAKE_CURRENT_SOURCE_DIR}/Core/BaseObject.py @@ -52,7 +52,7 @@ add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME}) set(DIR_BINDING_LIST Components - Config + Lifetime Core Helper Simulation diff --git a/bindings/Sofa/tests/Config/Config.py b/bindings/Sofa/tests/Config/Config.py deleted file mode 100644 index c285b698..00000000 --- a/bindings/Sofa/tests/Config/Config.py +++ /dev/null @@ -1,15 +0,0 @@ -# coding: utf8 - -import Sofa.Config -from Sofa.future import __enable_feature__ -import unittest - -class Test(unittest.TestCase): - def test_init_feature(self): - Sofa.Config.init("new_feature", False) - self.assertFalse(Sofa.Config.get("new_feature"), False) - - with __enable_feature__("new_feature", True): - self.assertEquals(Sofa.Config.get("new_feature"), True) - - self.assertFalse(Sofa.Config.get("new_feature"), False) diff --git a/bindings/Sofa/tests/Lifetime/Lifetime.py b/bindings/Sofa/tests/Lifetime/Lifetime.py new file mode 100644 index 00000000..30dd12c3 --- /dev/null +++ b/bindings/Sofa/tests/Lifetime/Lifetime.py @@ -0,0 +1,15 @@ +# coding: utf8 + +import Sofa.Lifetime +from Sofa.Lifetime import __feature__ +import unittest + +class Test(unittest.TestCase): + def test_init_feature(self): + Sofa.Lifetime.init("new_feature", False) + self.assertFalse(Sofa.Lifetimeg.get("new_feature"), False) + + with __feature__("new_feature", True): + self.assertEquals(Sofa.Lifetime.get("new_feature"), True) + + self.assertFalse(Sofa.Lifetime.get("new_feature"), False)