From dd20a6e42889d2c508127333cb9d0a4b13f1c9be Mon Sep 17 00:00:00 2001 From: Pranava Teja Surukuchi Date: Wed, 15 Jun 2022 16:57:16 -0400 Subject: [PATCH 1/5] Binding for controller --- Python/Bindings/CMakeLists.txt | 2 + Python/Bindings/Control/ControllerPybind.hh | 134 ++++++++++++++++++++ Python/Bindings/NymphPybind.cc | 2 + 3 files changed, 138 insertions(+) create mode 100644 Python/Bindings/Control/ControllerPybind.hh diff --git a/Python/Bindings/CMakeLists.txt b/Python/Bindings/CMakeLists.txt index 750528c..f2cf69f 100644 --- a/Python/Bindings/CMakeLists.txt +++ b/Python/Bindings/CMakeLists.txt @@ -9,12 +9,14 @@ set( TEST_DIR Testing/Cpp ) include_directories( BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/Data ${CMAKE_CURRENT_SOURCE_DIR}/Processor + ${CMAKE_CURRENT_SOURCE_DIR}/Control ) # Python binding headers set( PYBINDING_HEADERFILES Data/DataPybind.hh Processor/ProcessorPybind.hh + Control/ControllerPybind.hh ) # Python bindings diff --git a/Python/Bindings/Control/ControllerPybind.hh b/Python/Bindings/Control/ControllerPybind.hh new file mode 100644 index 0000000..34082ab --- /dev/null +++ b/Python/Bindings/Control/ControllerPybind.hh @@ -0,0 +1,134 @@ +/* + * ControllerPybind.hh + * + * Created on: June 15, 2022 + * Author: P. T. Surukuchi + */ + +#ifndef PYTHON_BINDINGS_PROCESSOR_CONTROLLERPYBIND_HH_ +#define PYTHON_BINDINGS_PROCESSOR_CONTROLLERPYBIND_HH_ + +#include +#include + +#include "Controller.hh" +#include "factory.hh" + +namespace py = pybind11; + +namespace NymphPybind +{ + //trampoline class, see https://pybind11.readthedocs.io/en/stable/advanced/classes.html + class PyController : public Nymph::Controller { + public: + /* Inherit the constructors */ + using Nymph::Controller::Controller; + + /* Trampoline (need one for each virtual function) */ + bool WaitToContinue() override { + PYBIND11_OVERRIDE( /* Using PYBIND11_OVERRIDE since this is for a function with default (non-pure) implementation*/ + bool, /* Return type */ + Controller, /* Parent class */ + WaitToContinue /* Name of function in C++ (must match Python name) */ + ); + } + + /* Trampoline */ + bool WaitForBreakOrCanceled() override { + PYBIND11_OVERRIDE( + bool, /* Return type */ + Controller, /* Parent class */ + WaitForBreakOrCanceled /* Name of function in C++ (must match Python name) */ + ); + } + + /* Trampoline */ + void WaitForEndOfRun() override { + PYBIND11_OVERRIDE( + void, /* Return type */ + Controller, /* Parent class */ + WaitForEndOfRun /* Name of function in C++ (must match Python name) */ + ); + } + + /* Trampoline */ + void Continue() override { + PYBIND11_OVERRIDE( + void, /* Return type */ + Controller, /* Parent class */ + Continue /* Name of function in C++ (must match Python name) */ + ); + } + + /* Trampoline */ + void Cancel( int code = 0 ) override { + PYBIND11_OVERRIDE( + void, /* Return type */ + Controller, /* Parent class */ + Cancel /* Name of function in C++ (must match Python name) */ + ); + } + + /* Trampoline */ + bool IsCanceled() const override { + PYBIND11_OVERRIDE( + bool, /* Return type */ + Controller, /* Parent class */ + IsCanceled /* Name of function in C++ (must match Python name) */ + ); + } + + /* Trampoline */ + void Break() override { + PYBIND11_OVERRIDE( + void, /* Return type */ + Controller, /* Parent class */ + Break /* Name of function in C++ (must match Python name) */ + ); + } + + /* Trampoline */ + bool IsAtBreak() const override { + PYBIND11_OVERRIDE( + bool, /* Return type */ + Controller, /* Parent class */ + IsAtBreak /* Name of function in C++ (must match Python name) */ + ); + } + + /* Trampoline */ + void ChainIsQuitting( const std::string& name, std::exception_ptr ePtr = std::exception_ptr() ) override { + PYBIND11_OVERRIDE( + void, /* Return type */ + Controller, /* Parent class */ + ChainIsQuitting, /* Name of function in C++ (must match Python name) */ + name, + ePtr + ); + } + }; + + // std::shared_ptr< Nymph::Controller > get_controller(const std::string& type, const std::string& name) + // { + // scarab::factory< Nymph::Controller, const std::string& >* factory = scarab::factory< Nymph::Controller, const std::string& >::get_instance(); + // return std::shared_ptr< Nymph::Controller >(factory->create(type, name)); + // } + + void ExportController( py::module_& nymphController) + { + py::class_< Nymph::Controller, PyController, std::shared_ptr >(nymphController, "_Controller") + .def(py::init< >()) + .def("WaitToContinue", &Nymph::Controller::WaitToContinue) + .def("WaitForBreakOrCanceled", &Nymph::Controller::WaitForBreakOrCanceled) + .def("WaitForEndOfRun", &Nymph::Controller::WaitForEndOfRun) + .def("Continue", &Nymph::Controller::Continue) + .def("Cancel", &Nymph::Controller::Cancel, py::arg("code") = 0 ) + .def("IsCanceled", &Nymph::Controller::IsCanceled) + .def("Break", &Nymph::Controller::Break) + .def("IsAtBreak", &Nymph::Controller::IsAtBreak) + .def("ChainIsQuitting", &Nymph::Controller::ChainIsQuitting, py::arg("name"), py::arg("ePtr") = std::exception_ptr() ); + } + +} + +#endif /* PYTHON_BINDINGS_PROCESSOR_PROCESSORPYBIND_HH_ */ diff --git a/Python/Bindings/NymphPybind.cc b/Python/Bindings/NymphPybind.cc index 56e5710..d240e59 100644 --- a/Python/Bindings/NymphPybind.cc +++ b/Python/Bindings/NymphPybind.cc @@ -10,6 +10,7 @@ #include "Processor/ProcessorPybind.hh" #include "Processor/SignalPybind.hh" #include "Data/DataPybind.hh" +#include "Control/ControllerPybind.hh" #include "DataFrame.hh" @@ -21,6 +22,7 @@ PYBIND11_MODULE(_nymph, nymphPackage) { nymphPackage.doc() = "Nymph package"; auto nymphControl = nymphPackage.def_submodule("control", "Control module"); + NymphPybind::ExportController(nymphControl); auto nymphData = nymphPackage.def_submodule("data", "Data module"); NymphPybind::ExportData(nymphData); auto nymphImplementation = nymphPackage.def_submodule("implementation", "Implementation module"); From acfc6180d27488e5b3e8056658d5c7872ba1d790 Mon Sep 17 00:00:00 2001 From: Pranava Teja Surukuchi Date: Thu, 16 Jun 2022 10:21:38 -0400 Subject: [PATCH 2/5] Moved use of _NAME for macros to be able to give non-identical python and cpp. Reverted to PEP 8 compliant naming for functions. --- Python/Bindings/Control/ControllerPybind.hh | 45 ++++++++++++--------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/Python/Bindings/Control/ControllerPybind.hh b/Python/Bindings/Control/ControllerPybind.hh index 34082ab..b309950 100644 --- a/Python/Bindings/Control/ControllerPybind.hh +++ b/Python/Bindings/Control/ControllerPybind.hh @@ -26,81 +26,90 @@ namespace NymphPybind /* Trampoline (need one for each virtual function) */ bool WaitToContinue() override { - PYBIND11_OVERRIDE( /* Using PYBIND11_OVERRIDE since this is for a function with default (non-pure) implementation*/ + PYBIND11_OVERRIDE_NAME( /* Using PYBIND11_OVERRIDE since this is for a function with default (non-pure) implementation*/ bool, /* Return type */ Controller, /* Parent class */ + "wait_to_continue", // Name of method in Python (name) WaitToContinue /* Name of function in C++ (must match Python name) */ ); } /* Trampoline */ bool WaitForBreakOrCanceled() override { - PYBIND11_OVERRIDE( + PYBIND11_OVERRIDE_NAME( bool, /* Return type */ Controller, /* Parent class */ + "wait_for_break_or_canceled", // Name of method in Python (name) WaitForBreakOrCanceled /* Name of function in C++ (must match Python name) */ ); } /* Trampoline */ void WaitForEndOfRun() override { - PYBIND11_OVERRIDE( + PYBIND11_OVERRIDE_NAME( void, /* Return type */ Controller, /* Parent class */ + "wait_for_end_of_run", // Name of method in Python (name) WaitForEndOfRun /* Name of function in C++ (must match Python name) */ ); } /* Trampoline */ void Continue() override { - PYBIND11_OVERRIDE( + PYBIND11_OVERRIDE_NAME( void, /* Return type */ Controller, /* Parent class */ + "continue", // Name of method in Python (name) Continue /* Name of function in C++ (must match Python name) */ ); } /* Trampoline */ void Cancel( int code = 0 ) override { - PYBIND11_OVERRIDE( + PYBIND11_OVERRIDE_PURE_NAME( void, /* Return type */ Controller, /* Parent class */ + "cancel", // Name of method in Python (name) Cancel /* Name of function in C++ (must match Python name) */ ); } /* Trampoline */ bool IsCanceled() const override { - PYBIND11_OVERRIDE( + PYBIND11_OVERRIDE_NAME( bool, /* Return type */ Controller, /* Parent class */ + "is_canceled", // Name of method in Python (name) IsCanceled /* Name of function in C++ (must match Python name) */ ); } /* Trampoline */ void Break() override { - PYBIND11_OVERRIDE( + PYBIND11_OVERRIDE_NAME( void, /* Return type */ Controller, /* Parent class */ + "break", // Name of method in Python (name) Break /* Name of function in C++ (must match Python name) */ ); } /* Trampoline */ bool IsAtBreak() const override { - PYBIND11_OVERRIDE( + PYBIND11_OVERRIDE_NAME( bool, /* Return type */ Controller, /* Parent class */ + "is_at_break", // Name of method in Python (name) IsAtBreak /* Name of function in C++ (must match Python name) */ ); } /* Trampoline */ void ChainIsQuitting( const std::string& name, std::exception_ptr ePtr = std::exception_ptr() ) override { - PYBIND11_OVERRIDE( + PYBIND11_OVERRIDE_NAME( void, /* Return type */ Controller, /* Parent class */ + "chain_is_quitting", // Name of method in Python (name) ChainIsQuitting, /* Name of function in C++ (must match Python name) */ name, ePtr @@ -118,15 +127,15 @@ namespace NymphPybind { py::class_< Nymph::Controller, PyController, std::shared_ptr >(nymphController, "_Controller") .def(py::init< >()) - .def("WaitToContinue", &Nymph::Controller::WaitToContinue) - .def("WaitForBreakOrCanceled", &Nymph::Controller::WaitForBreakOrCanceled) - .def("WaitForEndOfRun", &Nymph::Controller::WaitForEndOfRun) - .def("Continue", &Nymph::Controller::Continue) - .def("Cancel", &Nymph::Controller::Cancel, py::arg("code") = 0 ) - .def("IsCanceled", &Nymph::Controller::IsCanceled) - .def("Break", &Nymph::Controller::Break) - .def("IsAtBreak", &Nymph::Controller::IsAtBreak) - .def("ChainIsQuitting", &Nymph::Controller::ChainIsQuitting, py::arg("name"), py::arg("ePtr") = std::exception_ptr() ); + .def("wait_to_continue", &Nymph::Controller::WaitToContinue) + .def("wait_for_break_or_canceled", &Nymph::Controller::WaitForBreakOrCanceled) + .def("wait_for_end_of_run", &Nymph::Controller::WaitForEndOfRun) + .def("continue", &Nymph::Controller::Continue) + .def("cancel", &Nymph::Controller::Cancel, py::arg("code") = 0 ) + .def("is_canceled", &Nymph::Controller::IsCanceled) + .def("break", &Nymph::Controller::Break) + .def("is_at_break", &Nymph::Controller::IsAtBreak) + .def("chain_is_quitting", &Nymph::Controller::ChainIsQuitting, py::arg("name"), py::arg("ePtr") = std::exception_ptr() ); } } From ae2078d8d1c8e5e4d4f8d78030980f4fa3dcf672 Mon Sep 17 00:00:00 2001 From: Pranava Teja Surukuchi Date: Thu, 16 Jun 2022 11:39:38 -0400 Subject: [PATCH 3/5] Updated Scarab --- Scarab | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scarab b/Scarab index 0e1679e..ba065f6 160000 --- a/Scarab +++ b/Scarab @@ -1 +1 @@ -Subproject commit 0e1679e0567a98dc6bf213aacaf171b899934afd +Subproject commit ba065f66706217eaa748d9ddf82dd32bb17e6abe From ae2e191a5271c880e7d5bc7008a8cac166362144 Mon Sep 17 00:00:00 2001 From: Pranava Teja Surukuchi Date: Tue, 21 Jun 2022 17:02:05 -0400 Subject: [PATCH 4/5] Add test for controller --- Testing/Python/testcontroller.py | 61 ++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Testing/Python/testcontroller.py diff --git a/Testing/Python/testcontroller.py b/Testing/Python/testcontroller.py new file mode 100644 index 0000000..90a3d79 --- /dev/null +++ b/Testing/Python/testcontroller.py @@ -0,0 +1,61 @@ + +""" + testcontroller.py + + Created on: Jun 15, 2022 + Author: P. T. Surukuchi +""" +import unittest + +import _nymph + +'''Data class with integer variables''' +class TestController(_nymph.control._Controller): + + def __init__(self, test_var1=5): + super().__init__() + self.test_var1 = test_var1 + + def SetBreakFlag(flag): + self.B= + + +class TestControllerMethod(unittest.TestCase): + controller=TestController() + def test_idata_assignment(self): + self.assertEqual(self.data1.test_var1,0) + +if __name__ == '__main__': + unittest.main() + + + + +namespace Nymph +{ + class ControllerRevealer : public Controller + { + public: + using Controller::Controller; + virtual ~ControllerRevealer() {} + + void SetBreakFlag( bool flag ) + { + fBreakFlag = flag; + return; + } + + void SetCanceled( bool flag ) + { + f_canceled.store( flag ); + return; + } + + void do_cancellation( int code ) + { + Controller::do_cancellation( code ); + return; + } + }; +} + From 04c54f3dc57c7e8ef9846f83a5d41a1b7581bdf3 Mon Sep 17 00:00:00 2001 From: Pranava Teja Surukuchi Date: Tue, 21 Jun 2022 18:57:24 -0400 Subject: [PATCH 5/5] Small mods to testcontroller.py --- Testing/Python/testcontroller.py | 45 +++++++------------------------- 1 file changed, 10 insertions(+), 35 deletions(-) diff --git a/Testing/Python/testcontroller.py b/Testing/Python/testcontroller.py index 90a3d79..824bab0 100644 --- a/Testing/Python/testcontroller.py +++ b/Testing/Python/testcontroller.py @@ -9,53 +9,28 @@ import _nymph -'''Data class with integer variables''' class TestController(_nymph.control._Controller): def __init__(self, test_var1=5): super().__init__() self.test_var1 = test_var1 - def SetBreakFlag(flag): - self.B= + def set_break_flag(flag): + self.fBreakFlag=flag + def set_canceled(flag): + f_canceled.store(flag) + + def do_cancellation(flag): + _Controller.do_cancellation(code) class TestControllerMethod(unittest.TestCase): controller=TestController() def test_idata_assignment(self): - self.assertEqual(self.data1.test_var1,0) - + self.controller.SetCycleTimeMS( 100 ) + self.assertEqual(controller.GetCycleTimeMS(),0) + if __name__ == '__main__': unittest.main() - - -namespace Nymph -{ - class ControllerRevealer : public Controller - { - public: - using Controller::Controller; - virtual ~ControllerRevealer() {} - - void SetBreakFlag( bool flag ) - { - fBreakFlag = flag; - return; - } - - void SetCanceled( bool flag ) - { - f_canceled.store( flag ); - return; - } - - void do_cancellation( int code ) - { - Controller::do_cancellation( code ); - return; - } - }; -} -