summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Blum2013-03-17 17:38:40 -0700
committerJosh Blum2013-03-17 17:38:40 -0700
commit468d53f7797c63cda2ef9ba765f1066550d19ce4 (patch)
tree4008d74ee3138114799e9bf8434f8356e8ad804f
parent420f118ed61c52ae00b765b57be83bae910e0a60 (diff)
downloadsandhi-468d53f7797c63cda2ef9ba765f1066550d19ce4.tar.gz
sandhi-468d53f7797c63cda2ef9ba765f1066550d19ce4.tar.bz2
sandhi-468d53f7797c63cda2ef9ba765f1066550d19ce4.zip
gras: work on python hooks for props interface
-rw-r--r--include/gras/block.hpp13
-rw-r--r--include/gras/block.i1
-rw-r--r--lib/block_props.cpp21
-rw-r--r--python/gras/GRAS_Block.i59
-rw-r--r--python/gras/GRAS_HierBlock.i23
-rw-r--r--python/gras/GRAS_Utils.i43
-rw-r--r--tests/CMakeLists.txt13
-rw-r--r--tests/block_props_test.py53
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()