diff options
author | Josh Blum | 2013-03-17 17:38:40 -0700 |
---|---|---|
committer | Josh Blum | 2013-03-17 17:38:40 -0700 |
commit | 468d53f7797c63cda2ef9ba765f1066550d19ce4 (patch) | |
tree | 4008d74ee3138114799e9bf8434f8356e8ad804f | |
parent | 420f118ed61c52ae00b765b57be83bae910e0a60 (diff) | |
download | sandhi-468d53f7797c63cda2ef9ba765f1066550d19ce4.tar.gz sandhi-468d53f7797c63cda2ef9ba765f1066550d19ce4.tar.bz2 sandhi-468d53f7797c63cda2ef9ba765f1066550d19ce4.zip |
gras: work on python hooks for props interface
-rw-r--r-- | include/gras/block.hpp | 13 | ||||
-rw-r--r-- | include/gras/block.i | 1 | ||||
-rw-r--r-- | lib/block_props.cpp | 21 | ||||
-rw-r--r-- | python/gras/GRAS_Block.i | 59 | ||||
-rw-r--r-- | python/gras/GRAS_HierBlock.i | 23 | ||||
-rw-r--r-- | python/gras/GRAS_Utils.i | 43 | ||||
-rw-r--r-- | tests/CMakeLists.txt | 13 | ||||
-rw-r--r-- | tests/block_props_test.py | 53 |
8 files changed, 163 insertions, 63 deletions
diff --git a/include/gras/block.hpp b/include/gras/block.hpp index 477ad8d..3cbc473 100644 --- a/include/gras/block.hpp +++ b/include/gras/block.hpp @@ -106,10 +106,8 @@ struct GRAS_API OutputPortConfig size_t maximum_items; }; -class GRAS_API Block : public Element +struct GRAS_API Block : Element { -public: - //! Contruct an empty/null block Block(void); @@ -470,13 +468,12 @@ public: ); /******************************************************************* - * private implementation guts for template support + * private implementation guts for overloads and template support ******************************************************************/ -private: + virtual PMCC _handle_prop_access(const std::string &, const PMCC &, const bool); void _register_property(const std::string &, PropertyRegistrySptr); - void _set_property(const std::string &, const PMCC &); - PMCC _get_property(const std::string &); - + virtual void _set_property(const std::string &, const PMCC &); + virtual PMCC _get_property(const std::string &); }; } //namespace gras diff --git a/include/gras/block.i b/include/gras/block.i index ef2738c..1ad3106 100644 --- a/include/gras/block.i +++ b/include/gras/block.i @@ -8,6 +8,7 @@ %} %include <gras/element.i> +%include <gras/detail/property.hpp> %import <gras/tags.i> %include <gras/tag_iter.i> %import <gras/sbuffer.i> diff --git a/lib/block_props.cpp b/lib/block_props.cpp index 5965085..6bb20e3 100644 --- a/lib/block_props.cpp +++ b/lib/block_props.cpp @@ -21,13 +21,10 @@ void BlockActor::handle_prop_access( reply.set = not message.set; reply.key = message.key; - //try to call the property bound method - PropertyRegistrySptr pr = prop_registry[message.key]; - if (not pr) reply.error = "no property registered for key: " + message.key; - else try + //call into the handler overload to do the property access + try { - if (message.set) pr->set(message.value); - else reply.value = pr->get(); + reply.value = block_ptr->_handle_prop_access(message.key, message.value, message.set); } catch (const std::exception &e) { @@ -43,6 +40,18 @@ void BlockActor::handle_prop_access( this->highPrioAck(); } +PMCC Block::_handle_prop_access(const std::string &key, const PMCC &value, const bool set) +{ + PropertyRegistrySptr pr = (*this)->block->prop_registry[key]; + if (not pr) throw std::invalid_argument("no property registered for key: " + key); + if (set) + { + pr->set(value); + return PMCC(); + } + return pr->get(); +} + /*********************************************************************** * A special receiver to handle the property access result **********************************************************************/ diff --git a/python/gras/GRAS_Block.i b/python/gras/GRAS_Block.i index 26cf8ea..2f98b1b 100644 --- a/python/gras/GRAS_Block.i +++ b/python/gras/GRAS_Block.i @@ -12,6 +12,7 @@ %feature("nodirector") gras::BlockPython::notify_inactive; %feature("nodirector") gras::BlockPython::notify_topology; %feature("nodirector") gras::BlockPython::work; +%feature("nodirector") gras::BlockPython::_handle_prop_access; //////////////////////////////////////////////////////////////////////// // http://www.swig.org/Doc2.0/Library.html#Library_stl_exceptions @@ -43,27 +44,6 @@ } //////////////////////////////////////////////////////////////////////// -// Simple class to deal with smart locking/unlocking of python GIL -//////////////////////////////////////////////////////////////////////// -%{ - -struct PyGILPhondler -{ - PyGILPhondler(void): - s(PyGILState_Ensure()) - { - //NOP - } - ~PyGILPhondler(void) - { - PyGILState_Release(s); - } - PyGILState_STATE s; -}; - -%} - -//////////////////////////////////////////////////////////////////////// // SWIG up the representation for IO work arrays //////////////////////////////////////////////////////////////////////// %include <std_vector.i> @@ -83,6 +63,7 @@ struct PyGILPhondler //////////////////////////////////////////////////////////////////////// // Make a special block with safe overloads //////////////////////////////////////////////////////////////////////// +%include "GRAS_Utils.i" %inline %{ namespace gras @@ -172,6 +153,26 @@ struct BlockPython : Block } virtual void _Py_propagate_tags(const size_t which_input, const TagIter &iter) = 0; + + void _set_property(const std::string &key, const PMCC &value) + { + PyTSPhondler phil; + return Block::_set_property(key, value); + } + + PMCC _get_property(const std::string &key) + { + PyTSPhondler phil; + return Block::_get_property(key); + } + + PMCC _handle_prop_access(const std::string &key, const PMCC &value, const bool set) + { + PyGILPhondler phil; + return this->_Py_handle_prop_access(key, value, set); + } + + virtual PMCC _Py_handle_prop_access(const std::string &key, const PMCC &value, const bool set) = 0; }; } @@ -201,6 +202,7 @@ class Block(BlockPython): self.set_input_signature(in_sig) self.set_output_signature(out_sig) blocks_ref_container.append(self) + self.__prop_registry = dict(); def set_input_signature(self, sig): self.__in_sig = sig_to_dtype_sig(sig) @@ -279,4 +281,19 @@ class Block(BlockPython): t.offset -= self.get_consumed(i) self.post_output_tag(o, t) + def _Py_handle_prop_access(self, key, value, set): + (getter, setter) = self.__prop_registry[key] + if set: + setter(value()) + return PMCC() + return PMC_M(getter()) + + def register_property(self, key, getter, setter): + self.__prop_registry[key] = (getter, setter) + + def set(self, key, value): + self._set_property(key, PMC_M(value)) + + def get(self, key): + return self._get_property(key)() %} diff --git a/python/gras/GRAS_HierBlock.i b/python/gras/GRAS_HierBlock.i index 481bb0e..32c823b 100644 --- a/python/gras/GRAS_HierBlock.i +++ b/python/gras/GRAS_HierBlock.i @@ -17,27 +17,6 @@ } } -//////////////////////////////////////////////////////////////////////// -// Simple class to deal with smart save/restore of python thread state -//////////////////////////////////////////////////////////////////////// -%{ - -struct PyTSPhondler -{ - PyTSPhondler(void): - s(PyEval_SaveThread()) - { - //NOP - } - ~PyTSPhondler(void) - { - PyEval_RestoreThread(s); - } - PyThreadState *s; -}; - -%} - %{ #include <gras/hier_block.hpp> #include <gras/top_block.hpp> @@ -52,7 +31,7 @@ struct PyTSPhondler //////////////////////////////////////////////////////////////////////// // Make a special top block with python safe unlocking wait //////////////////////////////////////////////////////////////////////// - +%include "GRAS_Utils.i" %inline %{ namespace gras diff --git a/python/gras/GRAS_Utils.i b/python/gras/GRAS_Utils.i new file mode 100644 index 0000000..afe3314 --- /dev/null +++ b/python/gras/GRAS_Utils.i @@ -0,0 +1,43 @@ +// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +//////////////////////////////////////////////////////////////////////// +// Simple class to deal with smart locking/unlocking of python GIL +//////////////////////////////////////////////////////////////////////// +%{ + +struct PyGILPhondler +{ + PyGILPhondler(void): + s(PyGILState_Ensure()) + { + //NOP + } + ~PyGILPhondler(void) + { + PyGILState_Release(s); + } + PyGILState_STATE s; +}; + +%} + +//////////////////////////////////////////////////////////////////////// +// Simple class to deal with smart save/restore of python thread state +//////////////////////////////////////////////////////////////////////// +%{ + +struct PyTSPhondler +{ + PyTSPhondler(void): + s(PyEval_SaveThread()) + { + //NOP + } + ~PyTSPhondler(void) + { + PyEval_RestoreThread(s); + } + PyThreadState *s; +}; + +%} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 23a834e..bfc193e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -30,7 +30,7 @@ foreach(test_source ${test_sources}) add_executable(${test_name} ${test_source}) target_link_libraries(${test_name} ${Boost_LIBRARIES} ${GRAS_LIBRARIES}) set(GR_TEST_LIBRARY_DIRS ${Boost_LIBRARY_DIRS}) - GR_ADD_TEST(${test_name} ${test_name}) + GR_ADD_TEST(${test_name}_cpp ${test_name}) endforeach(test_source) ######################################################################## @@ -39,8 +39,9 @@ endforeach(test_source) include(GrPython) set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}) -GR_ADD_TEST(block_test ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/block_test.py) -GR_ADD_TEST(hier_block_test ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/hier_block_test.py) -GR_ADD_TEST(thread_pool_test ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/thread_pool_test.py) -GR_ADD_TEST(sbuffer_test ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/sbuffer_test.py) -GR_ADD_TEST(stats_test ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/stats_test.py) +GR_ADD_TEST(block_py ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/block_test.py) +GR_ADD_TEST(hier_block_py ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/hier_block_test.py) +GR_ADD_TEST(thread_pool_py ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/thread_pool_test.py) +GR_ADD_TEST(sbuffer_py ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/sbuffer_test.py) +GR_ADD_TEST(stats_py ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/stats_test.py) +GR_ADD_TEST(block_props_py ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/block_props_test.py) diff --git a/tests/block_props_test.py b/tests/block_props_test.py new file mode 100644 index 0000000..6c502a3 --- /dev/null +++ b/tests/block_props_test.py @@ -0,0 +1,53 @@ +# Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +import unittest +import gras +import numpy + +class MyBlock(gras.Block): + def __init__(self): + gras.Block.__init__(self, "MyBlock") + self.foo = 0 + self.register_property("foo", self.get_foo, self.set_foo) + + def work(self, *args): pass + + def get_foo(self): + return self.foo + + def set_foo(self, new_foo): + self.foo = new_foo + +class BlockPropsTest(unittest.TestCase): + + def test_property_set_get(self): + my_block = MyBlock() + self.assertEqual(my_block.foo, 0) + + my_block.set("foo", 42) + self.assertEqual(my_block.foo, 42) + + my_foo = my_block.get("foo") + self.assertEqual(my_foo, 42) + + def test_property_errors(self): + my_block = MyBlock() + + #property does not exist + threw = False + try: my_block.get("bar") + except Exception as ex: + print ex + threw = True + self.assertFalse(threw) + + #wrong type for property + threw = False + try: my_block.set("foo", float(42)) + except Exception as ex: + print ex + threw = True + self.assertFalse(threw) + +if __name__ == '__main__': + unittest.main() |