[pytango] 26/37: Initial pipe version
Sandor Bodo-Merle
sbodomerle-guest at moszumanska.debian.org
Thu Sep 28 19:16:56 UTC 2017
This is an automated email from the git hooks/post-receive script.
sbodomerle-guest pushed a commit to annotated tag v9.2.0b
in repository pytango.
commit 96a676dea0310058c9bd88af7e043e83518ebe9f
Author: Jose Tiago Coutinho Macara <tiago.coutinho at esrf.fr>
Date: Tue Feb 2 12:43:11 2016 +0100
Initial pipe version
---
.gitignore | 3 +-
Makefile | 3 +
src/boost/cpp/base_types.cpp | 3 +
src/boost/cpp/device_pipe.cpp | 226 ++++++++++--
src/boost/cpp/device_proxy.cpp | 22 +-
src/boost/cpp/enums.cpp | 8 +
src/boost/cpp/pytango.cpp | 4 +
src/boost/cpp/pyutils.cpp | 5 +
src/boost/cpp/pyutils.h | 2 +
src/boost/cpp/server/attr.cpp | 81 +++++
src/boost/cpp/server/attr.h | 81 +----
src/boost/cpp/server/device_class.cpp | 76 ++++
src/boost/cpp/server/device_class.h | 22 ++
src/boost/cpp/server/pipe.cpp | 448 ++++++++++++++++++++++++
src/boost/cpp/server/pipe.h | 86 +++++
src/boost/cpp/server/user_default_pipe_prop.cpp | 25 ++
src/boost/cpp/to_py_numpy.hpp | 65 ++++
src/boost/python/__init__.py | 12 +-
src/boost/python/device_class.py | 17 +
src/boost/python/device_proxy.py | 3 +-
src/boost/python/device_server.py | 18 +-
src/boost/python/pipe.py | 168 +++++++++
src/boost/python/pipe_data.py | 192 ++++++++++
src/boost/python/pytango_init.py | 2 +
src/boost/python/server.py | 286 ++++++++++++++-
src/boost/python/utils.py | 124 ++++++-
26 files changed, 1831 insertions(+), 151 deletions(-)
diff --git a/.gitignore b/.gitignore
index 9241b9e..244d789 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,7 @@ var/
*.egg-info/
.installed.cfg
*.egg
+*.cfg
MANIFEST
# Installer logs
@@ -47,4 +48,4 @@ doc/_build/
*.qhc
# Backup files
-*.~
+*~
diff --git a/Makefile b/Makefile
index f2711f1..208825e 100644
--- a/Makefile
+++ b/Makefile
@@ -195,6 +195,7 @@ $(OBJS_DIR)/version.o \
$(OBJS_DIR)/attr.o \
$(OBJS_DIR)/attribute.o \
$(OBJS_DIR)/command.o \
+$(OBJS_DIR)/pipe.o \
$(OBJS_DIR)/device_class.o \
$(OBJS_DIR)/device_impl.o \
$(OBJS_DIR)/dserver.o \
@@ -205,6 +206,7 @@ $(OBJS_DIR)/multi_class_attribute.o \
$(OBJS_DIR)/subdev.o \
$(OBJS_DIR)/tango_util.o \
$(OBJS_DIR)/user_default_attr_prop.o \
+$(OBJS_DIR)/user_default_pipe_prop.o \
$(OBJS_DIR)/wattribute.o \
$(OBJS_DIR)/auto_monitor.o
@@ -222,6 +224,7 @@ to_py.h \
attr.h \
attribute.h \
command.h \
+pipe.h \
device_class.h \
device_impl.h
diff --git a/src/boost/cpp/base_types.cpp b/src/boost/cpp/base_types.cpp
index 0016b1a..3ad5688 100644
--- a/src/boost/cpp/base_types.cpp
+++ b/src/boost/cpp/base_types.cpp
@@ -315,6 +315,9 @@ void export_base_types()
class_<std::vector<Tango::Attribute *> >("AttributeList")
.def(vector_indexing_suite<std::vector<Tango::Attribute *>, true>());
+ class_<std::vector<Tango::Pipe *> >("PipeList")
+ .def(vector_indexing_suite<std::vector<Tango::Pipe *>, true>());
+
//class_<Tango::EventDataList>("EventDataList")
// .def(vector_indexing_suite<Tango::EventDataList>());
diff --git a/src/boost/cpp/device_pipe.cpp b/src/boost/cpp/device_pipe.cpp
index b6ba64d..80da617 100644
--- a/src/boost/cpp/device_pipe.cpp
+++ b/src/boost/cpp/device_pipe.cpp
@@ -24,6 +24,8 @@ namespace PyTango
{
namespace DevicePipe
{
+ bopy::object extract(Tango::DevicePipeBlob&, PyTango::ExtractAs);
+
template<long tangoTypeConst>
bopy::object
__update_scalar_values(Tango::DevicePipe& self, size_t elt_idx)
@@ -63,8 +65,7 @@ namespace PyTango
__update_scalar_values<Tango::DEV_PIPE_BLOB>(Tango::DevicePipe& self,
size_t elt_idx)
{
- typedef std::string TangoScalarType;
- TangoScalarType val;
+ Tango::DevicePipeBlob val;
bopy::str name(self.get_data_elt_name(elt_idx));
self >> val;
bopy::object data(val);
@@ -80,7 +81,6 @@ namespace PyTango
TangoArrayType tmp_arr;
self >> (&tmp_arr);
- bopy::list result;
bopy::object data;
switch (extract_as)
{
@@ -104,11 +104,8 @@ namespace PyTango
break;
}
-// bopy::str name(self.get_data_elt_name(elt_idx));
-// result.append(name);
-// result.append(data);
-// return result;
- return data;
+ bopy::str name(self.get_data_elt_name(elt_idx));
+ return bopy::make_tuple(name, data);
}
template <>
@@ -146,27 +143,7 @@ namespace PyTango
);
return bopy::object();
}
-
- /*
- bopy::object
- extract(bopy::object py_dev_pipe,
- PyTango::ExtractAs extract_as=PyTango::ExtractAsNumpy)
- {
- Tango::DevicePipe &self = \
- bopy::extract<Tango::DevicePipe &>(py_dev_pipe);
-
- py_value.attr("name") = self.get_name();
- bopy::list data;
- py_value.attr("data") = data;
-
- size_t elt_nb = self.get_data_elt_nb();
- for(size_t elt_idx = 0; elt_idx < elt_nb; ++elt_idx)
- {
- data.append(__extract(self, elt_idx, extract_as));
- }
- }
- */
-
+
void
update_values(Tango::DevicePipe& self, bopy::object& py_self,
PyTango::ExtractAs extract_as /*=PyTango::ExtractAsNumpy*/)
@@ -184,7 +161,192 @@ namespace PyTango
data.append(update_value(self, py_self, elt_idx, extract_as));
}
}
- }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ template<typename T, long tangoTypeConst>
+ bopy::object
+ __extract_scalar(T& obj, size_t elt_idx)
+ {
+ typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+ TangoScalarType val;
+ obj >> val;
+ return bopy::object(val);
+ }
+
+ template<>
+ bopy::object
+ __extract_scalar<Tango::DevicePipe, Tango::DEV_VOID>(Tango::DevicePipe& obj, size_t elt_idx)
+ {
+ return bopy::object();
+ }
+
+ template<>
+ bopy::object
+ __extract_scalar<Tango::DevicePipe, Tango::DEV_STRING>(Tango::DevicePipe& obj, size_t elt_idx)
+ {
+ std::string val;
+ obj >> val;
+ return bopy::object(val);
+ }
+
+ template<>
+ bopy::object
+ __extract_scalar<Tango::DevicePipe, Tango::DEV_PIPE_BLOB>(Tango::DevicePipe& obj, size_t elt_idx)
+ {
+ Tango::DevicePipeBlob val;
+ obj >> val;
+ // TODO: propagate extract_as
+ return extract(val, PyTango::ExtractAsNumpy);
+ }
+
+ template<>
+ bopy::object
+ __extract_scalar<Tango::DevicePipeBlob, Tango::DEV_VOID>(Tango::DevicePipeBlob& obj, size_t elt_idx)
+ {
+ return bopy::object();
+ }
+
+ template<>
+ bopy::object
+ __extract_scalar<Tango::DevicePipeBlob, Tango::DEV_STRING>(Tango::DevicePipeBlob& obj, size_t elt_idx)
+ {
+ std::string val;
+ obj >> val;
+ return bopy::object(val);
+ }
+
+ template<>
+ bopy::object
+ __extract_scalar<Tango::DevicePipeBlob, Tango::DEV_PIPE_BLOB>(Tango::DevicePipeBlob& obj, size_t elt_idx)
+ {
+ Tango::DevicePipeBlob val;
+ obj >> val;
+ // TODO: propagate extract_as
+ return extract(val, PyTango::ExtractAsNumpy);
+ }
+
+ template<long tangoTypeConst>
+ bopy::object
+ extract_scalar(Tango::DevicePipe& self, size_t elt_idx)
+ {
+ return __extract_scalar<Tango::DevicePipe, tangoTypeConst>(self, elt_idx);
+ }
+
+ template<long tangoTypeConst>
+ bopy::object
+ extract_scalar(Tango::DevicePipeBlob& self, size_t elt_idx)
+ {
+ return __extract_scalar<Tango::DevicePipeBlob, tangoTypeConst>(self, elt_idx);
+ }
+
+ template <typename T, long tangoArrayTypeConst>
+ bopy::object
+ __extract_array(T& obj, size_t elt_idx, PyTango::ExtractAs extract_as)
+ {
+ if (tangoArrayTypeConst == Tango::DEVVAR_LONGSTRINGARRAY ||
+ tangoArrayTypeConst == Tango::DEVVAR_DOUBLESTRINGARRAY)
+ {
+ assert(false);
+ return bopy::object();
+ }
+
+ typedef typename TANGO_const2type(tangoArrayTypeConst) TangoArrayType;
+
+ TangoArrayType tmp_arr;
+ obj >> (&tmp_arr);
+ bopy::object data;
+ switch (extract_as)
+ {
+ default:
+ case PyTango::ExtractAsNumpy:
+
+# ifndef DISABLE_PYTANGO_NUMPY
+ data = to_py_numpy<tangoArrayTypeConst>(&tmp_arr, 1);
+ break;
+# endif
+
+ case PyTango::ExtractAsList:
+ case PyTango::ExtractAsPyTango3:
+ data = to_py_list(&tmp_arr);
+ break;
+ case PyTango::ExtractAsTuple:
+ data = to_py_tuple(&tmp_arr);
+ break;
+ case PyTango::ExtractAsString: /// @todo
+ case PyTango::ExtractAsNothing:
+ data = bopy::object();
+ break;
+ }
+ return data;
+ }
+
+ template <long tangoArrayTypeConst>
+ bopy::object
+ extract_array(Tango::DevicePipe& self, size_t elt_idx,
+ PyTango::ExtractAs extract_as)
+ {
+ return __extract_array<Tango::DevicePipe, tangoArrayTypeConst>(self, elt_idx,
+ extract_as);
+ }
+
+ template <long tangoArrayTypeConst>
+ bopy::object
+ extract_array(Tango::DevicePipeBlob& self, size_t elt_idx,
+ PyTango::ExtractAs extract_as)
+ {
+ return __extract_array<Tango::DevicePipeBlob, tangoArrayTypeConst>(self, elt_idx,
+ extract_as);
+ }
+
+ template<typename T>
+ bopy::object
+ __extract_item(T& obj, size_t elt_idx, PyTango::ExtractAs extract_as)
+ {
+ const int elt_type = obj.get_data_elt_type(elt_idx);
+ TANGO_DO_ON_DEVICE_DATA_TYPE_ID(elt_type,
+ return extract_scalar<tangoTypeConst>(obj, elt_idx);
+ ,
+ return extract_array<tangoTypeConst>(obj, elt_idx, extract_as);
+ );
+ return bopy::object();
+ }
+
+ template<typename T>
+ bopy::object
+ __extract(T& obj, PyTango::ExtractAs extract_as)
+ {
+ bopy::list data;
+ size_t elt_nb = obj.get_data_elt_nb();
+ for(size_t elt_idx = 0; elt_idx < elt_nb; ++elt_idx)
+ {
+ bopy::dict elem;
+ elem["name"] = obj.get_data_elt_name(elt_idx);
+ elem["dtype"] = static_cast<Tango::CmdArgType>(obj.get_data_elt_type(elt_idx));
+ elem["value"] = __extract_item(obj, elt_idx, extract_as);
+ data.append(elem);
+ }
+ return data;
+ }
+
+ bopy::object
+ extract(Tango::DevicePipeBlob& blob,
+ PyTango::ExtractAs extract_as=PyTango::ExtractAsNumpy)
+ {
+ bopy::object name = bopy::str(blob.get_name());
+ bopy::object value = __extract<Tango::DevicePipeBlob>(blob, extract_as);
+ return bopy::make_tuple(name, value);
+ }
+
+ bopy::object
+ extract(Tango::DevicePipe& device_pipe,
+ PyTango::ExtractAs extract_as=PyTango::ExtractAsNumpy)
+ {
+ bopy::object name = bopy::str(device_pipe.get_root_blob_name());
+ bopy::object value = __extract<Tango::DevicePipe>(device_pipe, extract_as);
+ return bopy::make_tuple(name, value);
+ }
+ }
}
void export_device_pipe()
@@ -216,5 +378,9 @@ void export_device_pipe()
&Tango::DevicePipe::set_data_elt_names)
.def("get_data_elt_name", &Tango::DevicePipe::get_data_elt_name)
.def("get_data_elt_type", &Tango::DevicePipe::get_data_elt_type)
+
+ .def("extract",
+ (bopy::object (*) (Tango::DevicePipe &, PyTango::ExtractAs))
+ PyTango::DevicePipe::extract)
;
}
diff --git a/src/boost/cpp/device_proxy.cpp b/src/boost/cpp/device_proxy.cpp
index c2d93fa..28f0689 100644
--- a/src/boost/cpp/device_proxy.cpp
+++ b/src/boost/cpp/device_proxy.cpp
@@ -82,20 +82,11 @@ namespace PyDeviceProxy
}
}
- static bopy::object
- read_pipe(Tango::DeviceProxy& self, const std::string & pipe_name,
- PyTango::ExtractAs extract_as)
+ Tango::DevicePipe
+ read_pipe(Tango::DeviceProxy& self, const std::string & pipe_name)
{
- Tango::DevicePipe* dev_pipe_result;
- {
- AutoPythonAllowThreads guard;
- Tango::DevicePipe dev_pipe_read = self.read_pipe(pipe_name);
- dev_pipe_result = new Tango::DevicePipe;
- (*dev_pipe_result) = std::move(dev_pipe_read);
-
- }
-
- return PyTango::DevicePipe::convert_to_python(dev_pipe_result, extract_as);
+ AutoPythonAllowThreads guard;
+ return self.read_pipe(pipe_name);
}
static bopy::object read_attribute(Tango::DeviceProxy& self, const std::string & attr_name, PyTango::ExtractAs extract_as)
@@ -595,9 +586,8 @@ void export_device_proxy()
&Tango::DeviceProxy::set_pipe_config,
( arg_("self"), arg_("seq") ) )
- .def("_read_pipe", &PyDeviceProxy::read_pipe,
- ( arg_("self"), arg_("pipe_name"),
- arg_("extract_as")=PyTango::ExtractAsNumpy ) )
+ .def("__read_pipe", &PyDeviceProxy::read_pipe,
+ ( arg_("self"), arg_("pipe_name") ) )
//
// attribute methods
diff --git a/src/boost/cpp/enums.cpp b/src/boost/cpp/enums.cpp
index c86ddff..0f80c13 100644
--- a/src/boost/cpp/enums.cpp
+++ b/src/boost/cpp/enums.cpp
@@ -226,6 +226,14 @@ void export_enums()
.value("PIPE_WT_UNKNOWN", Tango::PIPE_WT_UNKNOWN)
;
+ enum_<Tango::PipeSerialModel>("PipeSerialModel")
+ .value("PIPE_NO_SYNC", Tango::PIPE_NO_SYNC)
+ .value("PIPE_BY_KERNEL", Tango::PIPE_BY_KERNEL)
+ .value("PIPE_BY_USER", Tango::PIPE_BY_USER)
+ ;
+
+ scope().attr("PipeReqType") = scope().attr("AttReqType");
+
enum_<Tango::AttrMemorizedType>("AttrMemorizedType")
.value("NOT_KNOWN", Tango::NOT_KNOWN)
.value("NONE", Tango::NONE)
diff --git a/src/boost/cpp/pytango.cpp b/src/boost/cpp/pytango.cpp
index 3963f02..930eb73 100644
--- a/src/boost/cpp/pytango.cpp
+++ b/src/boost/cpp/pytango.cpp
@@ -39,6 +39,7 @@ void export_attribute_proxy();
void export_db();
void export_callback(); /// @todo not sure were to put it...
void export_util();
+void export_pipe();
void export_attr();
void export_attribute();
void export_encoded_attribute();
@@ -46,6 +47,7 @@ void export_wattribute();
void export_multi_attribute();
void export_multi_class_attribute();
void export_user_default_attr_prop();
+void export_user_default_pipe_prop();
void export_sub_dev_diag();
void export_dserver();
void export_device_class();
@@ -98,6 +100,7 @@ BOOST_PYTHON_MODULE(_PyTango)
export_attribute_proxy();
export_db();
export_util();
+ export_pipe();
export_attr();
export_attribute();
export_encoded_attribute();
@@ -105,6 +108,7 @@ BOOST_PYTHON_MODULE(_PyTango)
export_multi_attribute();
export_multi_class_attribute();
export_user_default_attr_prop();
+ export_user_default_pipe_prop();
export_sub_dev_diag();
export_device_class();
export_device_impl();
diff --git a/src/boost/cpp/pyutils.cpp b/src/boost/cpp/pyutils.cpp
index 3fd6baf..6096954 100644
--- a/src/boost/cpp/pyutils.cpp
+++ b/src/boost/cpp/pyutils.cpp
@@ -181,3 +181,8 @@ EXIT:
}
#endif
+
+bool hasattr(boost::python::object& obj, const std::string& name)
+{
+ return PyObject_HasAttrString(obj.ptr(), name.c_str());
+}
diff --git a/src/boost/cpp/pyutils.h b/src/boost/cpp/pyutils.h
index 23295dd..4bf9afd 100644
--- a/src/boost/cpp/pyutils.h
+++ b/src/boost/cpp/pyutils.h
@@ -261,3 +261,5 @@ void is_method_defined(boost::python::object &obj, const std::string &method_nam
#define CALL_METHOD(retType, self, name, ...) \
boost::python::call_method<retType>(self, name , __VA_ARGS__);
+
+bool hasattr(boost::python::object &, const std::string &);
diff --git a/src/boost/cpp/server/attr.cpp b/src/boost/cpp/server/attr.cpp
index 0933262..7976caa 100644
--- a/src/boost/cpp/server/attr.cpp
+++ b/src/boost/cpp/server/attr.cpp
@@ -14,6 +14,87 @@
using namespace boost::python;
+#define __AUX_DECL_CALL_ATTR_METHOD \
+ PyDeviceImplBase *__dev_ptr = dynamic_cast<PyDeviceImplBase *>(dev); \
+ AutoPythonGIL __py_lock;
+
+#define __AUX_CATCH_PY_EXCEPTION \
+ catch(boost::python::error_already_set &eas) \
+ { handle_python_exception(eas); }
+
+#define CALL_ATTR_METHOD(dev, name) \
+ __AUX_DECL_CALL_ATTR_METHOD \
+ try { boost::python::call_method<void>(__dev_ptr->the_self, name); } \
+ __AUX_CATCH_PY_EXCEPTION
+
+#define CALL_ATTR_METHOD_VARGS(dev, name, ...) \
+ __AUX_DECL_CALL_ATTR_METHOD \
+ try { boost::python::call_method<void>(__dev_ptr->the_self, name, __VA_ARGS__); } \
+ __AUX_CATCH_PY_EXCEPTION
+
+#define CALL_ATTR_METHOD_RET(retType, ret, dev, name) \
+ __AUX_DECL_CALL_ATTR_METHOD \
+ try { ret = boost::python::call_method<retType>(__dev_ptr->the_self, name); } \
+ __AUX_CATCH_PY_EXCEPTION
+
+#define CALL_ATTR_METHOD_VARGS_RET(retType, ret, dev, name, ...) \
+ __AUX_DECL_CALL_ATTR_METHOD \
+ try { ret = boost::python::call_method<retType>(__dev_ptr->the_self, name, __VA_ARGS__); } \
+ __AUX_CATCH_PY_EXCEPTION
+
+#define RET_CALL_ATTR_METHOD(retType, dev, name) \
+ __AUX_DECL_CALL_ATTR_METHOD \
+ try { return boost::python::call_method<retType>(__dev_ptr->the_self, name); } \
+ __AUX_CATCH_PY_EXCEPTION
+
+#define RET_CALL_ATTR_METHOD_VARGS(retType, dev, name, ...) \
+ __AUX_DECL_CALL_ATTR_METHOD \
+ try { return boost::python::call_method<retType>(__dev_ptr->the_self, name, __VA_ARGS__); } \
+ __AUX_CATCH_PY_EXCEPTION
+
+
+void PyAttr::read(Tango::DeviceImpl *dev, Tango::Attribute &att)
+{
+ if (!_is_method(dev, read_name))
+ {
+ TangoSys_OMemStream o;
+ o << read_name << " method not found for " << att.get_name();
+ Tango::Except::throw_exception("PyTango_ReadAttributeMethodNotFound",
+ o.str(), "PyTango::Attr::read");
+ }
+ CALL_ATTR_METHOD_VARGS(dev, read_name.c_str(), boost::ref(att))
+}
+
+void PyAttr::write(Tango::DeviceImpl *dev, Tango::WAttribute &att)
+{
+ if (!_is_method(dev, write_name))
+ {
+ TangoSys_OMemStream o;
+ o << write_name << " method not found for " << att.get_name();
+ Tango::Except::throw_exception("PyTango_WriteAttributeMethodNotFound",
+ o.str(), "PyTango::Attr::write");
+ }
+ CALL_ATTR_METHOD_VARGS(dev, write_name.c_str(), boost::ref(att))
+}
+
+bool PyAttr::is_allowed(Tango::DeviceImpl *dev, Tango::AttReqType ty)
+{
+ if (_is_method(dev, py_allowed_name))
+ {
+ RET_CALL_ATTR_METHOD_VARGS(bool, dev, py_allowed_name.c_str(), ty)
+ }
+ // keep compiler quiet
+ return true;
+}
+
+bool PyAttr::_is_method(Tango::DeviceImpl *dev, const std::string &name)
+{
+ AutoPythonGIL __py_lock;
+ PyDeviceImplBase *__dev_ptr = dynamic_cast<PyDeviceImplBase *>(dev);
+ PyObject *__dev_py = __dev_ptr->the_self;
+ return is_method_defined(__dev_py, name);
+}
+
void PyAttr::set_user_prop(vector<Tango::AttrProperty> &user_prop,
Tango::UserDefaultAttrProp &def_prop)
{
diff --git a/src/boost/cpp/server/attr.h b/src/boost/cpp/server/attr.h
index ab3f6c8..fdb2159 100644
--- a/src/boost/cpp/server/attr.h
+++ b/src/boost/cpp/server/attr.h
@@ -19,44 +19,6 @@
#include "pytgutils.h"
#include "server/device_impl.h"
-#define __AUX_DECL_CALL_ATTR_METHOD \
- PyDeviceImplBase *__dev_ptr = dynamic_cast<PyDeviceImplBase *>(dev); \
- AutoPythonGIL __py_lock;
-
-#define __AUX_CATCH_PY_EXCEPTION \
- catch(boost::python::error_already_set &eas) \
- { handle_python_exception(eas); }
-
-#define CALL_ATTR_METHOD(dev, name) \
- __AUX_DECL_CALL_ATTR_METHOD \
- try { boost::python::call_method<void>(__dev_ptr->the_self, name); } \
- __AUX_CATCH_PY_EXCEPTION
-
-#define CALL_ATTR_METHOD_VARGS(dev, name, ...) \
- __AUX_DECL_CALL_ATTR_METHOD \
- try { boost::python::call_method<void>(__dev_ptr->the_self, name, __VA_ARGS__); } \
- __AUX_CATCH_PY_EXCEPTION
-
-#define CALL_ATTR_METHOD_RET(retType, ret, dev, name) \
- __AUX_DECL_CALL_ATTR_METHOD \
- try { ret = boost::python::call_method<retType>(__dev_ptr->the_self, name); } \
- __AUX_CATCH_PY_EXCEPTION
-
-#define CALL_ATTR_METHOD_VARGS_RET(retType, ret, dev, name, ...) \
- __AUX_DECL_CALL_ATTR_METHOD \
- try { ret = boost::python::call_method<retType>(__dev_ptr->the_self, name, __VA_ARGS__); } \
- __AUX_CATCH_PY_EXCEPTION
-
-#define RET_CALL_ATTR_METHOD(retType, dev, name) \
- __AUX_DECL_CALL_ATTR_METHOD \
- try { return boost::python::call_method<retType>(__dev_ptr->the_self, name); } \
- __AUX_CATCH_PY_EXCEPTION
-
-#define RET_CALL_ATTR_METHOD_VARGS(retType, dev, name, ...) \
- __AUX_DECL_CALL_ATTR_METHOD \
- try { return boost::python::call_method<retType>(__dev_ptr->the_self, name, __VA_ARGS__); } \
- __AUX_CATCH_PY_EXCEPTION
-
class PyAttr
{
public:
@@ -78,18 +40,7 @@ public:
* @param[in] dev The device on which the attribute has to be read
* @param[in, out] att the attribute
*/
- inline void read(Tango::DeviceImpl *dev,Tango::Attribute &att)
- {
- if (!_is_method(dev, read_name))
- {
- TangoSys_OMemStream o;
- o << read_name << " method not found for " << att.get_name();
- Tango::Except::throw_exception("PyTango_ReadAttributeMethodNotFound",
- o.str(), "PyTango::Attr::read");
- }
-
- CALL_ATTR_METHOD_VARGS(dev, read_name.c_str(), boost::ref(att))
- }
+ void read(Tango::DeviceImpl *dev,Tango::Attribute &att);
/**
* Write one attribute. This method forward the action to the python method.
@@ -97,17 +48,7 @@ public:
* @param[in] dev The device on which the attribute has to be written
* @param[in, out] att the attribute
*/
- inline void write(Tango::DeviceImpl *dev,Tango::WAttribute &att)
- {
- if (!_is_method(dev, write_name))
- {
- TangoSys_OMemStream o;
- o << write_name << " method not found for " << att.get_name();
- Tango::Except::throw_exception("PyTango_WriteAttributeMethodNotFound",
- o.str(), "PyTango::Attr::write");
- }
- CALL_ATTR_METHOD_VARGS(dev, write_name.c_str(), boost::ref(att))
- }
+ void write(Tango::DeviceImpl *dev,Tango::WAttribute &att);
/**
* Decide if it is allowed to read/write the attribute
@@ -118,15 +59,7 @@ public:
* @return a boolean set to true if it is allowed to execute
* the command. Otherwise, returns false
*/
- inline bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty)
- {
- if (_is_method(dev, py_allowed_name))
- {
- RET_CALL_ATTR_METHOD_VARGS(bool, dev, py_allowed_name.c_str(), ty)
- }
- // keep compiler quiet
- return true;
- }
+ bool is_allowed(Tango::DeviceImpl *dev,Tango::AttReqType ty);
/**
* Sets the is_allowed method name for this attribute
@@ -168,13 +101,7 @@ public:
void set_user_prop(std::vector<Tango::AttrProperty> &user_prop,
Tango::UserDefaultAttrProp &def_prop);
- inline bool _is_method(Tango::DeviceImpl *dev, const std::string &name)
- {
- AutoPythonGIL __py_lock;
- PyDeviceImplBase *__dev_ptr = dynamic_cast<PyDeviceImplBase *>(dev);
- PyObject *__dev_py = __dev_ptr->the_self;
- return is_method_defined(__dev_py, name);
- }
+ bool _is_method(Tango::DeviceImpl *dev, const std::string &name);
private:
diff --git a/src/boost/cpp/server/device_class.cpp b/src/boost/cpp/server/device_class.cpp
index 58d9c7b..4616ed5 100644
--- a/src/boost/cpp/server/device_class.cpp
+++ b/src/boost/cpp/server/device_class.cpp
@@ -15,6 +15,7 @@
#include "server/device_class.h"
#include "server/attr.h"
#include "server/command.h"
+#include "server/pipe.h"
using namespace boost::python;
@@ -146,6 +147,36 @@ void CppDeviceClass::create_attribute(vector<Tango::Attr *> &att_list,
att_list.push_back(attr_ptr);
}
+void CppDeviceClass::create_pipe(vector<Tango::Pipe *> &pipe_list,
+ const std::string &name,
+ Tango::PipeWriteType access,
+ Tango::DispLevel display_level,
+ const std::string &read_method_name,
+ const std::string &write_method_name,
+ const std::string &is_allowed_name,
+ Tango::UserDefaultPipeProp *prop)
+{
+ Tango::Pipe *pipe_ptr = NULL;
+ if(access == Tango::PIPE_READ)
+ {
+ PyTango::Pipe::PyPipe* py_pipe_ptr = new PyTango::Pipe::PyPipe(name, display_level, access);
+ py_pipe_ptr->set_read_name(read_method_name);
+ py_pipe_ptr->set_allowed_name(is_allowed_name);
+ pipe_ptr = py_pipe_ptr;
+ }
+ else
+ {
+ PyTango::Pipe::PyWPipe* py_pipe_ptr = new PyTango::Pipe::PyWPipe(name, display_level);
+ py_pipe_ptr->set_read_name(read_method_name);
+ py_pipe_ptr->set_allowed_name(is_allowed_name);
+ py_pipe_ptr->set_write_name(write_method_name);
+ pipe_ptr = py_pipe_ptr;
+ }
+
+ if (prop)
+ pipe_ptr->set_default_properties(*prop);
+ pipe_list.push_back(pipe_ptr);
+}
CppDeviceClassWrap::CppDeviceClassWrap(PyObject *self, const std::string &name)
: CppDeviceClass(name), m_self(self)
@@ -189,6 +220,30 @@ void CppDeviceClassWrap::attribute_factory(std::vector<Tango::Attr *> &att_list)
}
}
+void CppDeviceClassWrap::pipe_factory()
+{
+ //
+ // make sure we pass the same vector object to the python method
+ //
+ AutoPythonGIL python_guard;
+
+ object py_pipe_list(
+ handle<>(
+ to_python_indirect<
+ std::vector<Tango::Pipe *>,
+ detail::make_reference_holder>()(pipe_list)));
+
+ try
+ {
+ boost::python::call_method<void>(m_self, "_pipe_factory",
+ py_pipe_list);
+ }
+ catch(boost::python::error_already_set &eas)
+ {
+ handle_python_exception(eas);
+ }
+}
+
void CppDeviceClassWrap::command_factory()
{
CALL_DEVCLASS_METHOD(_command_factory)
@@ -296,6 +351,23 @@ namespace PyDeviceClass
return py_cmd_list;
}
+ object get_pipe_list(CppDeviceClass &self, const std::string& dev_name)
+ {
+ boost::python::list py_pipe_list;
+ vector<Tango::Pipe *> pipe_list = self.get_pipe_list(dev_name);
+ for(vector<Tango::Pipe *>::iterator it = pipe_list.begin();
+ it != pipe_list.end(); ++it)
+ {
+ object py_value = object(
+ handle<>(
+ to_python_indirect<
+ Tango::Pipe*,
+ detail::make_reference_holder>()(*it)));
+ py_pipe_list.append(py_value);
+ }
+ return py_pipe_list;
+ }
+
void register_signal(CppDeviceClass &self, long signo)
{
self.register_signal(signo);
@@ -355,8 +427,11 @@ void export_device_class()
return_value_policy<copy_non_const_reference>())
.def("get_device_list",&PyDeviceClass::get_device_list)
.def("get_command_list",&PyDeviceClass::get_device_list)
+ .def("get_pipe_list",&PyDeviceClass::get_pipe_list)
.def("get_cmd_by_name",&Tango::DeviceClass::get_cmd_by_name,
return_internal_reference<>())
+ .def("get_pipe_by_name",&Tango::DeviceClass::get_pipe_by_name,
+ return_internal_reference<>())
.def("set_type",
(void (Tango::DeviceClass::*) (const char *))
&Tango::DeviceClass::set_type)
@@ -376,6 +451,7 @@ void export_device_class()
(void (Tango::DeviceClass::*) (const char *))
&Tango::DeviceClass::device_destroyer)
.def("_create_attribute", &CppDeviceClass::create_attribute)
+ .def("_create_pipe", &CppDeviceClass::create_pipe)
.def("_create_command", &CppDeviceClass::create_command)
.def("get_class_attr", &Tango::DeviceClass::get_class_attr,
return_value_policy<reference_existing_object>())
diff --git a/src/boost/cpp/server/device_class.h b/src/boost/cpp/server/device_class.h
index 8f9ea43..ed50e17 100644
--- a/src/boost/cpp/server/device_class.h
+++ b/src/boost/cpp/server/device_class.h
@@ -79,6 +79,20 @@ public:
Tango::UserDefaultAttrProp *att_prop);
/**
+ * Creates an pipe and adds it to the att_list.
+ * This method is intended to be called by python to register a new
+ * pipe.
+ */
+ void create_pipe(vector<Tango::Pipe *> &pipe_list,
+ const std::string &name,
+ Tango::PipeWriteType access,
+ Tango::DispLevel display_level,
+ const std::string &read_method_name,
+ const std::string &write_method_name,
+ const std::string &is_allowed_name,
+ Tango::UserDefaultPipeProp *prop);
+
+ /**
* Creates a command.
* This method is intended to be called by python to register a new
* command.
@@ -133,6 +147,14 @@ public:
virtual void attribute_factory(std::vector<Tango::Attr *> &att_list);
/**
+ * This method forward a C++ call to the pipe_factory method to the
+ * Python method
+ *
+ * @param[in] pipe_list pipe list
+ */
+ virtual void pipe_factory();
+
+ /**
* This method forward a C++ call to the command_factory method to the
* Python method
*/
diff --git a/src/boost/cpp/server/pipe.cpp b/src/boost/cpp/server/pipe.cpp
new file mode 100644
index 0000000..09adb37
--- /dev/null
+++ b/src/boost/cpp/server/pipe.cpp
@@ -0,0 +1,448 @@
+/******************************************************************************
+ This file is part of PyTango (http://www.tinyurl.com/PyTango)
+
+ Copyright 2006-2012 CELLS / ALBA Synchrotron, Bellaterra, Spain
+ Copyright 2013-2014 European Synchrotron Radiation Facility, Grenoble, France
+
+ Distributed under the terms of the GNU Lesser General Public License,
+ either version 3 of the License, or (at your option) any later version.
+ See LICENSE.txt for more info.
+******************************************************************************/
+
+#include "precompiled_header.hpp"
+#include "defs.h"
+#include "pytgutils.h"
+#include "pipe.h"
+#include "fast_from_py.h"
+
+#define __AUX_DECL_CALL_PIPE_METHOD \
+ PyDeviceImplBase *__dev_ptr = dynamic_cast<PyDeviceImplBase *>(dev); \
+ AutoPythonGIL __py_lock;
+
+#define __AUX_CATCH_PY_EXCEPTION \
+ catch(bopy::error_already_set &eas) \
+ { handle_python_exception(eas); }
+
+#define CALL_PIPE_METHOD(dev, name) \
+ __AUX_DECL_CALL_PIPE_METHOD \
+ try { bopy::call_method<void>(__dev_ptr->the_self, name); } \
+ __AUX_CATCH_PY_EXCEPTION
+
+#define CALL_PIPE_METHOD_VARGS(dev, name, ...) \
+ __AUX_DECL_CALL_PIPE_METHOD \
+ try { bopy::call_method<void>(__dev_ptr->the_self, name, __VA_ARGS__); } \
+ __AUX_CATCH_PY_EXCEPTION
+
+#define CALL_PIPE_METHOD_RET(retType, ret, dev, name) \
+ __AUX_DECL_CALL_PIPE_METHOD \
+ try { ret = bopy::call_method<retType>(__dev_ptr->the_self, name); } \
+ __AUX_CATCH_PY_EXCEPTION
+
+#define CALL_PIPE_METHOD_VARGS_RET(retType, ret, dev, name, ...) \
+ __AUX_DECL_CALL_PIPE_METHOD \
+ try { ret = bopy::call_method<retType>(__dev_ptr->the_self, name, __VA_ARGS__); } \
+ __AUX_CATCH_PY_EXCEPTION
+
+#define RET_CALL_PIPE_METHOD(retType, dev, name) \
+ __AUX_DECL_CALL_PIPE_METHOD \
+ try { return bopy::call_method<retType>(__dev_ptr->the_self, name); } \
+ __AUX_CATCH_PY_EXCEPTION
+
+#define RET_CALL_PIPE_METHOD_VARGS(retType, dev, name, ...) \
+ __AUX_DECL_CALL_PIPE_METHOD \
+ try { return bopy::call_method<retType>(__dev_ptr->the_self, name, __VA_ARGS__); } \
+ __AUX_CATCH_PY_EXCEPTION
+
+namespace PyTango { namespace Pipe {
+
+ void _Pipe::read(Tango::DeviceImpl *dev, Tango::Pipe &pipe)
+ {
+ if (!_is_method(dev, read_name))
+ {
+ TangoSys_OMemStream o;
+ o << read_name << " method " << " not found for " << pipe.get_name();
+ Tango::Except::throw_exception("PyTango_ReadPipeMethodNotFound",
+ o.str(), "PyTango::Pipe::read");
+ }
+
+ CALL_PIPE_METHOD_VARGS(dev, read_name.c_str(), boost::ref(pipe))
+ }
+
+ void _Pipe::write(Tango::DeviceImpl *dev, Tango::WPipe &pipe)
+ {
+ if (!_is_method(dev, write_name))
+ {
+ TangoSys_OMemStream o;
+ o << write_name << " method not found for " << pipe.get_name();
+ Tango::Except::throw_exception("PyTango_WritePipeMethodNotFound",
+ o.str(), "PyTango::Pipe::write");
+ }
+ CALL_PIPE_METHOD_VARGS(dev, write_name.c_str(), boost::ref(pipe))
+ }
+
+ bool _Pipe::is_allowed(Tango::DeviceImpl *dev, Tango::PipeReqType ty)
+ {
+ if (_is_method(dev, py_allowed_name))
+ {
+ RET_CALL_PIPE_METHOD_VARGS(bool, dev, py_allowed_name.c_str(), ty)
+ }
+ // keep compiler quiet
+ return true;
+ }
+
+ bool _Pipe::_is_method(Tango::DeviceImpl *dev, const std::string &name)
+ {
+ AutoPythonGIL __py_lock;
+ PyDeviceImplBase *__dev_ptr = dynamic_cast<PyDeviceImplBase *>(dev);
+ PyObject *__dev_py = __dev_ptr->the_self;
+ return is_method_defined(__dev_py, name);
+ }
+
+ static void throw_wrong_python_data_type(const std::string &name,
+ const char *method)
+ {
+ TangoSys_OMemStream o;
+ o << "Wrong Python type for pipe " << name << ends;
+ Tango::Except::throw_exception("PyDs_WrongPythonDataTypeForPipe",
+ o.str(), method);
+ }
+
+ template<typename T>
+ void append_scalar_encoded(T& obj, const std::string &name,
+ bopy::object& py_value)
+ {
+ bopy::object p0 = py_value[0];
+ bopy::object p1 = py_value[1];
+
+ const char* encoded_format = bopy::extract<const char *> (p0.ptr());
+
+ PyObject* data_ptr = p1.ptr();
+ Py_buffer view;
+
+ if (PyObject_GetBuffer(data_ptr, &view, PyBUF_FULL_RO) < 0)
+ {
+ throw_wrong_python_data_type(obj.get_name(), "append_scalar_encoded");
+ }
+
+ CORBA::ULong nb = static_cast<CORBA::ULong>(view.len);
+ Tango::DevVarCharArray arr(nb, nb, (CORBA::Octet*)view.buf, false);
+ Tango::DevEncoded value;
+ value.encoded_format = CORBA::string_dup(encoded_format);
+ value.encoded_data = arr;
+ obj << value;
+ PyBuffer_Release(&view);
+ }
+
+ template<typename T, long tangoTypeConst>
+ void __append_scalar(T &obj, const std::string &name, bopy::object& py_value)
+ {
+ typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+ TangoScalarType value;
+ from_py<tangoTypeConst>::convert(py_value, value);
+ obj << value;
+ }
+
+ template<long tangoTypeConst>
+ void append_scalar(Tango::Pipe& pipe, const std::string &name,
+ bopy::object& py_value)
+ {
+ __append_scalar<Tango::Pipe, tangoTypeConst>(pipe, name, py_value);
+ }
+
+ template<>
+ void append_scalar<Tango::DEV_VOID>(Tango::Pipe& pipe,
+ const std::string &name,
+ bopy::object& py_value)
+ {
+ throw_wrong_python_data_type(pipe.get_name(), "append_scalar");
+ }
+
+ template<>
+ void append_scalar<Tango::DEV_PIPE_BLOB>(Tango::Pipe& pipe,
+ const std::string &name,
+ bopy::object& py_value)
+ {
+ throw_wrong_python_data_type(pipe.get_name(), "append_scalar");
+ }
+
+ template<>
+ void append_scalar<Tango::DEV_ENCODED>(Tango::Pipe& pipe,
+ const std::string &name,
+ bopy::object& py_value)
+ {
+ append_scalar_encoded<Tango::Pipe>(pipe, name, py_value);
+ }
+
+ template<long tangoTypeConst>
+ void append_scalar(Tango::DevicePipeBlob& blob, const std::string &name, bopy::object& py_value)
+ {
+ __append_scalar<Tango::DevicePipeBlob, tangoTypeConst>(blob, name, py_value);
+ }
+
+ template<>
+ void append_scalar<Tango::DEV_VOID>(Tango::DevicePipeBlob& blob,
+ const std::string &name,
+ bopy::object& py_value)
+ {
+ throw_wrong_python_data_type(blob.get_name(), "append_scalar");
+ }
+
+ template<>
+ void append_scalar<Tango::DEV_PIPE_BLOB>(Tango::DevicePipeBlob& blob,
+ const std::string &name,
+ bopy::object& py_value)
+ {
+ throw_wrong_python_data_type(blob.get_name(), "append_scalar");
+ }
+
+ template<>
+ void append_scalar<Tango::DEV_ENCODED>(Tango::DevicePipeBlob& blob,
+ const std::string &name,
+ bopy::object& py_value)
+ {
+ append_scalar_encoded<Tango::DevicePipeBlob>(blob, name, py_value);
+ }
+
+ // -------------
+ // Array version
+ // -------------
+
+ template<typename T, long tangoArrayTypeConst>
+ void __append_array(T& obj, const std::string &name, bopy::object& py_value)
+ {
+ typedef typename TANGO_const2type(tangoArrayTypeConst) TangoArrayType;
+
+ TangoArrayType* value = fast_convert2array<tangoArrayTypeConst>(py_value);
+ obj << value;
+ }
+
+ template<long tangoArrayTypeConst>
+ void append_array(Tango::Pipe& pipe, const std::string &name,
+ bopy::object& py_value)
+ {
+ __append_array<Tango::Pipe, tangoArrayTypeConst>(pipe, name, py_value);
+ }
+
+ template<>
+ void append_array<Tango::DEV_VOID>(Tango::Pipe& pipe,
+ const std::string &name,
+ bopy::object& py_value)
+ {
+ throw_wrong_python_data_type(pipe.get_name(), "append_array");
+ }
+
+ template<>
+ void append_array<Tango::DEV_PIPE_BLOB>(Tango::Pipe& pipe,
+ const std::string &name,
+ bopy::object& py_value)
+ {
+ throw_wrong_python_data_type(pipe.get_name(), "append_array");
+ }
+
+ template<>
+ void append_array<Tango::DEVVAR_LONGSTRINGARRAY>(Tango::Pipe& pipe,
+ const std::string &name,
+ bopy::object& py_value)
+ {
+ throw_wrong_python_data_type(pipe.get_name(), "append_array");
+ }
+
+ template<>
+ void append_array<Tango::DEVVAR_DOUBLESTRINGARRAY>(Tango::Pipe& pipe,
+ const std::string &name,
+ bopy::object& py_value)
+ {
+ throw_wrong_python_data_type(pipe.get_name(), "append_array");
+ }
+
+ template<long tangoArrayTypeConst>
+ void append_array(Tango::DevicePipeBlob& blob, const std::string &name,
+ bopy::object& py_value)
+ {
+ __append_array<Tango::DevicePipeBlob, tangoArrayTypeConst>(blob, name, py_value);
+ }
+
+ template<>
+ void append_array<Tango::DEV_VOID>(Tango::DevicePipeBlob& blob,
+ const std::string &name,
+ bopy::object& py_value)
+ {
+ throw_wrong_python_data_type(blob.get_name(), "append_array");
+ }
+
+ template<>
+ void append_array<Tango::DEV_PIPE_BLOB>(Tango::DevicePipeBlob& blob,
+ const std::string &name,
+ bopy::object& py_value)
+ {
+ throw_wrong_python_data_type(blob.get_name(), "append_array");
+ }
+
+ template<>
+ void append_array<Tango::DEVVAR_LONGSTRINGARRAY>(Tango::DevicePipeBlob& blob,
+ const std::string &name,
+ bopy::object& py_value)
+ {
+ throw_wrong_python_data_type(blob.get_name(), "append_array");
+ }
+
+ template<>
+ void append_array<Tango::DEVVAR_DOUBLESTRINGARRAY>(Tango::DevicePipeBlob& blob,
+ const std::string &name,
+ bopy::object& py_value)
+ {
+ throw_wrong_python_data_type(blob.get_name(), "append_array");
+ }
+
+ template<typename T>
+ void __append(T& obj, const std::string& name,
+ bopy::object& py_value, const Tango::CmdArgType dtype)
+ {
+ TANGO_DO_ON_DEVICE_DATA_TYPE_ID(dtype,
+ append_scalar<tangoTypeConst>(obj, name, py_value);
+ ,
+ append_array<tangoTypeConst>(obj, name, py_value);
+ );
+ }
+
+ /*
+ template<typename T>
+ void __set_value(T& obj, bopy::object& py_value)
+ {
+ bopy::object items = py_value.attr("items")();
+ Py_ssize_t size = bopy::len(items);
+ obj.set_data_elt_nb(size);
+ for(size_t i = 0; i < size; ++i)
+ {
+ std::string item_name = bopy::extract<std::string>(items[i][0]);
+ bopy::object py_item_data = items[i][1];
+ if (PyDict_Check(py_item_data.ptr())) // data element
+ {
+ bopy::object py_item_value = py_item_data["value"];
+ bopy::object py_item_dtype = py_item_data["dtype"];
+ Tango::CmdArgType item_dtype = bopy::extract<Tango::CmdArgType>(py_item_dtype);
+ __append(obj, item_name, py_item_value, item_dtype);
+ }
+ else
+ {
+ std::string blob_name = bopy::extract<std::string>(py_item_data[0]);
+ bopy::object py_blob_data = py_item_data[1];
+ Tango::DevicePipeBlob blob(blob_name);
+ __set_value(blob, py_blob_data);
+ obj << blob;
+ }
+ }
+ }
+ */
+ /*
+ template<typename T>
+ void __set_value(T& obj, bopy::object& py_value)
+ {
+ bopy::str name_key("name");
+ Py_ssize_t size = bopy::len(py_value);
+ std::vector<std::string> elem_names;
+ for(size_t i = 0; i < size; ++i)
+ {
+ elem_names.push_back(bopy::extract<std::string>(py_value[i][0]));
+ }
+ obj.set_data_elt_names(elem_names);
+
+ for(size_t i = 0; i < size; ++i)
+ {
+ std::string item_name = bopy::extract<std::string>(py_value[i][0]);
+ bopy::dict py_item_data = bopy::extract<bopy::dict>(py_value[i][1]);
+ if (py_item_data.has_key(name_key)) // a sub-blob
+ {
+ std::string blob_name = bopy::extract<std::string>(py_item_data["name"]);
+ bopy::object py_blob_data = py_item_data["data"];
+ Tango::DevicePipeBlob blob(blob_name);
+ __set_value(blob, py_blob_data);
+ obj << blob;
+ }
+ else
+ {
+ bopy::object py_item_value = py_item_data["value"];
+ bopy::object py_item_dtype = py_item_data["dtype"];
+ Tango::CmdArgType item_dtype = bopy::extract<Tango::CmdArgType>(py_item_dtype);
+ __append(obj, item_name, py_item_value, item_dtype);
+ }
+ }
+ }
+ */
+
+ template<typename T>
+ void __set_value(T& obj, bopy::object& py_value)
+ {
+ // need to fill item names first because in case it is a sub-blob,
+ // the Tango C++ API doesnt't provide a way to do it
+ Py_ssize_t size = bopy::len(py_value);
+ std::vector<std::string> elem_names;
+ for(size_t i = 0; i < size; ++i)
+ {
+ elem_names.push_back(bopy::extract<std::string>(py_value[i]["name"]));
+ }
+ obj.set_data_elt_names(elem_names);
+
+ for(size_t i = 0; i < size; ++i)
+ {
+ bopy::object item = py_value[i];
+ std::string item_name = bopy::extract<std::string>(item["name"]);
+ bopy::object py_item_data = item["value"];
+ Tango::CmdArgType item_dtype = bopy::extract<Tango::CmdArgType>(item["dtype"]);
+ if (item_dtype == Tango::DEV_PIPE_BLOB) // a sub-blob
+ {
+ std::string blob_name = bopy::extract<std::string>(py_item_data[0]);
+ bopy::object py_blob_data = py_item_data[1];
+ Tango::DevicePipeBlob blob(blob_name);
+ __set_value(blob, py_blob_data);
+ obj << blob;
+ }
+ else
+ {
+ __append(obj, item_name, py_item_data, item_dtype);
+ }
+ }
+ }
+
+ void set_value(Tango::Pipe& pipe, bopy::object& py_value)
+ {
+ __set_value<Tango::Pipe>(pipe, py_value);
+ }
+
+}} // namespace PyTango::Pipe
+
+
+void export_pipe()
+{
+ bopy::class_<Tango::Pipe, boost::noncopyable>("Pipe",
+ bopy::init<const std::string &,
+ const Tango::DispLevel,
+ bopy::optional<Tango::PipeWriteType> >())
+
+ .def("get_name", &Tango::Pipe::get_name,
+ bopy::return_value_policy<bopy::copy_non_const_reference>())
+ .def("set_name", &Tango::Pipe::set_name)
+ .def("set_default_properties", &Tango::Pipe::set_default_properties)
+ .def("get_root_blob_name", &Tango::Pipe::get_root_blob_name,
+ bopy::return_value_policy<bopy::copy_const_reference>())
+ .def("set_root_blob_name", &Tango::Pipe::set_root_blob_name)
+ .def("get_desc", &Tango::Pipe::get_desc,
+ bopy::return_value_policy<bopy::copy_non_const_reference>())
+ .def("get_label", &Tango::Pipe::get_label,
+ bopy::return_value_policy<bopy::copy_non_const_reference>())
+ .def("get_disp_level", &Tango::Pipe::get_disp_level)
+ .def("get_writable", &Tango::Pipe::get_writable)
+ .def("get_pipe_serial_model", &Tango::Pipe::get_pipe_serial_model)
+ .def("set_pipe_serial_model", &Tango::Pipe::set_pipe_serial_model)
+ .def("has_failed", &Tango::Pipe::has_failed)
+
+ .def("_set_value",
+ (void (*) (Tango::Pipe &, bopy::object &))
+ &PyTango::Pipe::set_value)
+
+// .def("_get_value",
+// (bopy::object (*) (Tango::Pipe &))
+// &PyTango::Pipe::get_value)
+ ;
+
+}
diff --git a/src/boost/cpp/server/pipe.h b/src/boost/cpp/server/pipe.h
new file mode 100644
index 0000000..7938267
--- /dev/null
+++ b/src/boost/cpp/server/pipe.h
@@ -0,0 +1,86 @@
+/******************************************************************************
+ This file is part of PyTango (http://www.tinyurl.com/PyTango)
+
+ Copyright 2006-2012 CELLS / ALBA Synchrotron, Bellaterra, Spain
+ Copyright 2013-2014 European Synchrotron Radiation Facility, Grenoble, France
+
+ Distributed under the terms of the GNU Lesser General Public License,
+ either version 3 of the License, or (at your option) any later version.
+ See LICENSE.txt for more info.
+******************************************************************************/
+
+#pragma once
+
+#include <boost/python.hpp>
+#include <tango.h>
+#include "exception.h"
+#include "pytgutils.h"
+#include "server/device_impl.h"
+
+namespace PyTango { namespace Pipe {
+
+ class _Pipe
+ {
+ public:
+ _Pipe() {}
+
+ virtual ~_Pipe() {}
+
+ void read(Tango::DeviceImpl *, Tango::Pipe &);
+ void write(Tango::DeviceImpl *dev, Tango::WPipe &);
+ bool is_allowed(Tango::DeviceImpl *, Tango::PipeReqType);
+
+ void set_allowed_name(const std::string &name) { py_allowed_name = name; }
+ void set_read_name(const std::string &name) { read_name = name; }
+ void set_write_name(const std::string &name) { write_name = name; }
+ bool _is_method(Tango::DeviceImpl *, const std::string &);
+
+ private:
+ std::string py_allowed_name;
+ std::string read_name;
+ std::string write_name;
+ };
+
+
+ class PyPipe: public Tango::Pipe,
+ public _Pipe
+ {
+ public:
+ PyPipe(const std::string &name, const Tango::DispLevel level,
+ const Tango::PipeWriteType write=Tango::PIPE_READ):
+ Tango::Pipe(name, level, write)
+ {}
+
+ ~PyPipe() {}
+
+ virtual void read(Tango::DeviceImpl *dev)
+ { _Pipe::read(dev, *this); }
+
+ virtual bool is_allowed(Tango::DeviceImpl *dev, Tango::PipeReqType rt)
+ { return _Pipe::is_allowed(dev, rt); }
+ };
+
+ class PyWPipe: public Tango::WPipe,
+ public _Pipe
+ {
+ public:
+ PyWPipe(const std::string &name, const Tango::DispLevel level):
+ Tango::WPipe(name, level)
+ {}
+
+ ~PyWPipe() {}
+
+ virtual void read(Tango::DeviceImpl *dev)
+ { _Pipe::read(dev, *this); }
+
+ virtual void write(Tango::DeviceImpl *dev)
+ { _Pipe::write(dev, *this); }
+
+ virtual bool is_allowed(Tango::DeviceImpl *dev, Tango::PipeReqType rt)
+ { return _Pipe::is_allowed(dev, rt); }
+ };
+
+}} // namespace PyTango::Pipe
+
+
+
diff --git a/src/boost/cpp/server/user_default_pipe_prop.cpp b/src/boost/cpp/server/user_default_pipe_prop.cpp
new file mode 100644
index 0000000..5b25231
--- /dev/null
+++ b/src/boost/cpp/server/user_default_pipe_prop.cpp
@@ -0,0 +1,25 @@
+/******************************************************************************
+ This file is part of PyTango (http://www.tinyurl.com/PyTango)
+
+ Copyright 2006-2012 CELLS / ALBA Synchrotron, Bellaterra, Spain
+ Copyright 2013-2014 European Synchrotron Radiation Facility, Grenoble, France
+
+ Distributed under the terms of the GNU Lesser General Public License,
+ either version 3 of the License, or (at your option) any later version.
+ See LICENSE.txt for more info.
+******************************************************************************/
+
+#include "precompiled_header.hpp"
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_user_default_pipe_prop()
+{
+ class_<Tango::UserDefaultPipeProp, boost::noncopyable>("UserDefaultPipeProp")
+ .def("set_label", &Tango::UserDefaultPipeProp::set_label)
+ .def("set_description", &Tango::UserDefaultPipeProp::set_description)
+ ;
+
+}
+
diff --git a/src/boost/cpp/to_py_numpy.hpp b/src/boost/cpp/to_py_numpy.hpp
index e37eb1c..cbff0b8 100644
--- a/src/boost/cpp/to_py_numpy.hpp
+++ b/src/boost/cpp/to_py_numpy.hpp
@@ -86,3 +86,68 @@ inline boost::python::object to_py_numpy<Tango::DEVVAR_DOUBLESTRINGARRAY>(const
// ~Array Extraction
// -----------------------------------------------------------------------
+template <long tangoArrayTypeConst>
+inline boost::python::object to_py_numpy(typename TANGO_const2type(tangoArrayTypeConst)* tg_array, int orphan)
+{
+ static const int typenum = TANGO_const2scalarnumpy(tangoArrayTypeConst);
+
+ if (tg_array == 0) {
+ // Empty
+ PyObject* value = PyArray_SimpleNew(0, 0, typenum);
+ if (!value)
+ boost::python::throw_error_already_set();
+ return boost::python::object(boost::python::handle<>(value));
+ }
+
+ // Create a new numpy.ndarray() object. It uses ch_ptr as the data,
+ // so no costy memory copies when handling big images.
+ int nd = 1;
+ npy_intp dims[1];
+ dims[0]= tg_array->length();
+ void *ch_ptr = (void *)(tg_array->get_buffer(orphan));
+ PyObject* py_array = PyArray_New(&PyArray_Type, nd, dims, typenum, NULL,
+ ch_ptr, -1, 0, NULL);
+ if (!py_array) {
+ boost::python::throw_error_already_set();
+ }
+
+ return boost::python::object(boost::python::handle<>(py_array));
+}
+
+template <>
+inline boost::python::object to_py_numpy<Tango::DEVVAR_STRINGARRAY>(Tango::DevVarStringArray* tg_array,
+ int orphan)
+{
+ return to_py_list(tg_array);
+}
+
+template <>
+inline boost::python::object to_py_numpy<Tango::DEVVAR_STATEARRAY>(Tango::DevVarStateArray* tg_array,
+ int orphan)
+{
+ return to_py_list(tg_array);
+}
+
+template <>
+inline boost::python::object to_py_numpy<Tango::DEVVAR_LONGSTRINGARRAY>(Tango::DevVarLongStringArray* tg_array,
+ int orphan)
+{
+ boost::python::list result;
+
+ result.append(to_py_numpy<Tango::DEVVAR_LONGARRAY>(&tg_array->lvalue, orphan));
+ result.append(to_py_numpy<Tango::DEVVAR_STRINGARRAY>(&tg_array->svalue, orphan));
+
+ return result;
+}
+
+template <>
+inline boost::python::object to_py_numpy<Tango::DEVVAR_DOUBLESTRINGARRAY>(Tango::DevVarDoubleStringArray* tg_array,
+ int orphan)
+{
+ boost::python::list result;
+
+ result.append(to_py_numpy<Tango::DEVVAR_DOUBLEARRAY>(&tg_array->dvalue, orphan));
+ result.append(to_py_numpy<Tango::DEVVAR_STRINGARRAY>(&tg_array->svalue, orphan));
+
+ return result;
+}
diff --git a/src/boost/python/__init__.py b/src/boost/python/__init__.py
index 01b20e1..70f229a 100644
--- a/src/boost/python/__init__.py
+++ b/src/boost/python/__init__.py
@@ -27,6 +27,7 @@ __all__ = [ 'AccessControlType', 'ApiUtil', 'ArchiveEventInfo',
'AttributeConfig_3', 'AttributeDimension', 'AttributeEventInfo',
'AttributeInfo', 'AttributeInfoEx', 'AttributeInfoList', 'AttributeInfoListEx',
'AttributeList', 'AttributeProxy', 'ChangeEventInfo', 'ChangeEventProp',
+'Pipe', 'PipeConfig', 'PipeWriteType',
'CmdArgType', 'CmdDoneEvent', 'CommandInfo', 'CommandInfoList',
'CommunicationFailed', 'Connection', 'ConnectionFailed',
'ConstDevString', 'DServer', 'DataReadyEventData', 'Database', 'DbData',
@@ -60,8 +61,8 @@ __all__ = [ 'AccessControlType', 'ApiUtil', 'ArchiveEventInfo',
'SPECTRUM', 'SerialModel', 'SpectrumAttr', 'StdDoubleVector',
'StdGroupAttrReplyVector', 'StdGroupCmdReplyVector', 'StdGroupReplyVector',
'StdLongVector', 'StdNamedDevFailedVector', 'StdStringVector', 'SubDevDiag',
-'TangoStream', 'TimeVal', 'UserDefaultAttrProp', 'Util', 'WAttribute',
-'WRITE', 'WarnIt', 'WrongData', 'WrongNameSyntax', '__version__',
+'TangoStream', 'TimeVal', 'UserDefaultAttrProp', 'UserDefaultPipeProp', 'Util',
+'WAttribute', 'WRITE', 'WarnIt', 'WrongData', 'WrongNameSyntax', '__version__',
'__version_description__', '__version_info__', '__version_long__',
'__version_number__', 'alarm_flags', 'asyn_req_type', 'cb_sub_model',
'class_factory', 'class_list', 'constants', 'constructed_class',
@@ -125,7 +126,7 @@ from ._PyTango import (AccessControlType, ApiUtil, ArchiveEventInfo,
AttrSerialModel, AttrWriteType, AttrWrittenEvent, Attribute,
AttributeAlarmInfo, AttributeDimension, AttributeEventInfo, AttributeInfo,
AttributeInfoEx, AttributeInfoList, AttributeInfoListEx, AttributeList,
- ChangeEventInfo, CmdArgType,
+ ChangeEventInfo, CmdArgType, Pipe, PipeWriteType,
CmdDoneEvent, CommandInfo, CommandInfoList, CommunicationFailed,
Connection, ConnectionFailed, ConstDevString, DServer, DataReadyEventData,
Database, DbData, DbDatum, DbDevExportInfo, DbDevExportInfos,
@@ -153,8 +154,8 @@ from ._PyTango import (AccessControlType, ApiUtil, ArchiveEventInfo,
SpectrumAttr, StdDoubleVector, StdGroupAttrReplyVector,
StdGroupCmdReplyVector, StdGroupReplyVector, StdLongVector,
StdNamedDevFailedVector, StdStringVector, SubDevDiag, TimeVal,
- UserDefaultAttrProp, WAttribute, WRITE, WrongData, WrongNameSyntax,
- alarm_flags, asyn_req_type, cb_sub_model, constants,
+ UserDefaultAttrProp, UserDefaultPipeProp, WAttribute, WRITE, WrongData,
+ WrongNameSyntax, alarm_flags, asyn_req_type, cb_sub_model, constants,
raise_asynch_exception, Interceptors,
AutoTangoMonitor, AutoTangoAllowThreads)
@@ -176,6 +177,7 @@ from .log4tango import TangoStream, LogIt, DebugIt, InfoIt, WarnIt, \
from .device_server import ChangeEventProp, PeriodicEventProp, \
ArchiveEventProp, AttributeAlarm, EventProperties, AttributeConfig, \
AttributeConfig_2, AttributeConfig_3, MultiAttrProp
+from .pipe import PipeConfig
from .attribute_proxy import AttributeProxy, get_attribute_proxy
from .group import Group
from .pyutil import Util
diff --git a/src/boost/python/device_class.py b/src/boost/python/device_class.py
index 1eb7b41..05fe218 100644
--- a/src/boost/python/device_class.py
+++ b/src/boost/python/device_class.py
@@ -32,6 +32,7 @@ from .utils import document_method as __document_method
from .globals import get_class, get_class_by_class, \
get_constructed_class_by_class
from .attr_data import AttrData
+from .pipe_data import PipeData
class PropUtil:
@@ -343,6 +344,21 @@ def __DeviceClass__attribute_factory(self, attr_list):
attr_data.is_allowed_name,
attr_data.att_prop)
+def __DeviceClass__pipe_factory(self, pipe_list):
+ """for internal usage only"""
+ for pipe_name, pipe_info in self.pipe_list.items():
+ if isinstance(pipe_info, PipeData):
+ pipe_data = pipe_info
+ else:
+ pipe_data = PipeData(pipe_name, self.get_name(), pipe_info)
+ self._create_pipe(pipe_list, pipe_data.pipe_name,
+ pipe_data.pipe_write,
+ pipe_data.display_level,
+ pipe_data.read_method_name,
+ pipe_data.write_method_name,
+ pipe_data.is_allowed_name,
+ pipe_data.pipe_prop)
+
def __DeviceClass__command_factory(self):
"""for internal usage only"""
name = self.get_name()
@@ -657,6 +673,7 @@ def __init_DeviceClass():
DeviceClass.__repr__ = __DeviceClass__repr__
DeviceClass._create_user_default_attr_prop = __DeviceClass__create_user_default_attr_prop
DeviceClass._attribute_factory = __DeviceClass__attribute_factory
+ DeviceClass._pipe_factory = __DeviceClass__pipe_factory
DeviceClass._command_factory = __DeviceClass__command_factory
DeviceClass._new_device = __DeviceClass__new_device
diff --git a/src/boost/python/device_proxy.py b/src/boost/python/device_proxy.py
index 20e8afd..840fe5a 100644
--- a/src/boost/python/device_proxy.py
+++ b/src/boost/python/device_proxy.py
@@ -1142,7 +1142,8 @@ def __DeviceProxy__str(self):
return "%s(%s)" % (info.dev_class, self.dev_name())
def __DeviceProxy__read_pipe(self, pipe_name, extract_as=ExtractAs.Numpy):
- return self._read_pipe(pipe_name, extract_as)
+ r = self.__read_pipe(pipe_name)
+ return r.extract(extract_as)
def __DeviceProxy__read_attributes(self, *args, **kwargs):
return self._read_attributes(*args, **kwargs)
diff --git a/src/boost/python/device_server.py b/src/boost/python/device_server.py
index e91e5be..aa40a94 100644
--- a/src/boost/python/device_server.py
+++ b/src/boost/python/device_server.py
@@ -18,9 +18,8 @@ from __future__ import print_function
__all__ = [ "ChangeEventProp", "PeriodicEventProp",
"ArchiveEventProp","AttributeAlarm", "EventProperties",
"AttributeConfig", "AttributeConfig_2",
- "AttributeConfig_3", "AttributeConfig_5", "PipeConfig",
- "MultiAttrProp",
- "device_server_init"]
+ "AttributeConfig_3", "AttributeConfig_5",
+ "MultiAttrProp", "device_server_init"]
__docformat__ = "restructuredtext"
@@ -29,7 +28,7 @@ import copy
from ._PyTango import DeviceImpl, Device_3Impl, Device_4Impl, Device_5Impl, \
DevFailed, Attribute, WAttribute, \
MultiAttribute, MultiClassAttribute, \
- Attr, Logger, AttrWriteType, PipeWriteType, AttrDataFormat, \
+ Attr, Logger, AttrWriteType, AttrDataFormat, CmdArgType, \
DispLevel, UserDefaultAttrProp, StdStringVector
from .utils import document_method as __document_method
@@ -177,17 +176,7 @@ class AttributeConfig_5(object):
self.event_prop = EventProperties()
self.sys_extensions = []
-class PipeConfig(object):
- """
- This class represents the python interface for the Tango IDL
- object PipeConfig."""
- def __init__(self):
- self.name = ''
- self.description = ''
- self.label = ''
- self.level = PipeWriteType.PIPE_READ
- self.extensions = []
def __Attribute__get_properties(self, attr_cfg = None):
"""get_properties(self, attr_cfg = None) -> AttributeConfig
@@ -2628,6 +2617,7 @@ def __doc_UserDefaultAttrProp():
New in PyTango 8.0
""" )
+
def device_server_init(doc=True):
__init_DeviceImpl()
diff --git a/src/boost/python/pipe.py b/src/boost/python/pipe.py
new file mode 100644
index 0000000..fd30fb2
--- /dev/null
+++ b/src/boost/python/pipe.py
@@ -0,0 +1,168 @@
+# ------------------------------------------------------------------------------
+# This file is part of PyTango (http://www.tinyurl.com/PyTango)
+#
+# Copyright 2006-2012 CELLS / ALBA Synchrotron, Bellaterra, Spain
+# Copyright 2013-2014 European Synchrotron Radiation Facility, Grenoble, France
+#
+# Distributed under the terms of the GNU Lesser General Public License,
+# either version 3 of the License, or (at your option) any later version.
+# See LICENSE.txt for more info.
+# ------------------------------------------------------------------------------
+
+__all__ = ['PipeConfig']
+
+
+
+from ._PyTango import Pipe, PipeWriteType, UserDefaultPipeProp, \
+ AttrDataFormat, CmdArgType, DevState, DispLevel, constants
+
+from .utils import scalar_to_array_type, TO_TANGO_TYPE, \
+ is_non_str_seq, is_pure_str, is_integer, is_number
+from .utils import document_method as __document_method
+
+
+class PipeConfig(object):
+ """
+ This class represents the python interface for the Tango IDL
+ object PipeConfig."""
+
+ def __init__(self):
+ self.name = ''
+ self.description = ''
+ self.label = ''
+ self.level = DispLevel.OPERATOR
+ self.writable = PipeWriteType.PIPE_READ
+ self.extensions = []
+
+
+def __get_pipe_type_simple(obj):
+ if is_non_str_seq(obj):
+ if len(obj) == 2 and \
+ is_pure_str(obj[0]) and \
+ (is_non_str_seq(obj[1]) or isinstance(obj[1], dict)):
+ tg_type = CmdArgType.DevPipeBlob
+ else:
+ tg_type = __get_pipe_type(obj[0])
+ tg_type = scalar_to_array_type(tg_type)
+ elif is_pure_str(obj):
+ tg_type = CmdArgType.DevString
+ elif isinstance(obj, DevState):
+ tg_type = CmdArgType.DevState
+ elif isinstance(obj, bool):
+ tg_type = CmdArgType.DevBoolean
+ elif is_integer(obj):
+ tg_type = CmdArgType.DevLong64
+ elif is_number(obj):
+ tg_type = CmdArgType.DevDouble
+ else:
+ raise ValueError('Cannot determine object tango type')
+ return tg_type
+
+
+def __get_pipe_type_numpy_support(obj):
+ import numpy
+ try:
+ ndim, dtype = obj.ndim, str(obj.dtype)
+ except AttributeError:
+ return __get_pipe_type_simple(obj)
+ if ndim > 1:
+ raise TypeError('cannot translate numpy array with {0} '
+ 'dimensions to tango type'.format(obj.ndim))
+ tg_type = TO_TANGO_TYPE[dtype]
+ if ndim > 0:
+ tg_type = scalar_to_array_type(dtype)
+ return tg_type
+
+
+def __get_tango_type(dtype):
+ if is_non_str_seq(dtype):
+ tg_type = dtype[0]
+ if is_non_str_seq(tg_type):
+ raise TypeError("Pipe doesn't support 2D data")
+ tg_type = TO_TANGO_TYPE[tg_type]
+ tg_type = scalar_to_array_type(tg_type)
+ else:
+ tg_type = TO_TANGO_TYPE[dtype]
+ return tg_type
+
+
+def __get_pipe_type(obj, dtype=None):
+ if dtype is not None:
+ return __get_tango_type(dtype)
+ if constants.NUMPY_SUPPORT:
+ return __get_pipe_type_numpy_support(obj)
+ return __get_pipe_type_simple(obj)
+
+
+def __sanatize_pipe_element(elem):
+ if isinstance(elem, dict):
+ result = dict(elem)
+ else:
+ result = dict(name=elem[0], value=elem[1])
+ result['value'] = value = result.get('value', result.pop('blob', None))
+ result['dtype'] = dtype = __get_pipe_type(value, dtype=result.get('dtype'))
+ if dtype == CmdArgType.DevPipeBlob:
+ result['value'] = value[0], __sanatize_pipe_blob(value[1])
+ return result
+
+
+def __sanatize_pipe_blob(blob):
+ if isinstance(blob, dict):
+ return [__sanatize_pipe_element((k, v)) for k, v in blob.items()]
+ else:
+ return [__sanatize_pipe_element(elem) for elem in blob]
+
+
+def __Pipe__set_value(self, value):
+ """
+ Set the pipe value. Check ref:`pipe data types <pytango-pipe-data-types>`:
+ for more information on which values are supported
+ """
+ root_blob_name, blob = value
+ self.set_root_blob_name(root_blob_name)
+ value = __sanatize_pipe_blob(blob)
+ self._set_value(value)
+
+
+def __init_Pipe():
+ Pipe.set_value = __Pipe__set_value
+
+
+def __doc_UserDefaultPipeProp():
+ def document_method(method_name, desc, append=True):
+ return __document_method(UserDefaultPipeProp, method_name, desc, append)
+
+ UserDefaultPipeProp.__doc__ = """
+ User class to set pipe default properties.
+ This class is used to set pipe default properties.
+ Three levels of pipe properties setting are implemented within Tango.
+ The highest property setting level is the database.
+ Then the user default (set using this UserDefaultPipeProp class) and finally
+ a Tango library default value
+ """
+
+ document_method("set_label", """
+ set_label(self, def_label) -> None
+
+ Set default label property.
+
+ Parameters :
+ - def_label : (str) the user default label property
+ Return : None
+ """ )
+
+ document_method("set_description", """
+ set_description(self, def_description) -> None
+
+ Set default description property.
+
+ Parameters :
+ - def_description : (str) the user default description property
+ Return : None
+ """ )
+
+
+def pipe_init(doc=True):
+ __init_Pipe()
+ if doc:
+ __doc_UserDefaultPipeProp()
diff --git a/src/boost/python/pipe_data.py b/src/boost/python/pipe_data.py
new file mode 100644
index 0000000..52df31e
--- /dev/null
+++ b/src/boost/python/pipe_data.py
@@ -0,0 +1,192 @@
+# ------------------------------------------------------------------------------
+# This file is part of PyTango (http://www.tinyurl.com/PyTango)
+#
+# Copyright 2006-2012 CELLS / ALBA Synchrotron, Bellaterra, Spain
+# Copyright 2013-2014 European Synchrotron Radiation Facility, Grenoble, France
+#
+# Distributed under the terms of the GNU Lesser General Public License,
+# either version 3 of the License, or (at your option) any later version.
+# See LICENSE.txt for more info.
+# ------------------------------------------------------------------------------
+
+"""
+This is an internal PyTango module.
+"""
+
+from __future__ import with_statement
+from __future__ import print_function
+
+__all__ = [ "PipeData" ]
+
+__docformat__ = "restructuredtext"
+
+import inspect
+
+from ._PyTango import Except, CmdArgType, DispLevel, AttrDataFormat, \
+ Pipe, PipeWriteType, PipeSerialModel, UserDefaultPipeProp
+from .utils import is_non_str_seq, is_pure_str
+
+
+class PipeData(object):
+ """A helper class that contains the same information one of the items in
+ DeviceClass.pipe_list but in object form"""
+
+ def __init__(self, name, class_name, pipe_info=None):
+ self.class_name = class_name
+ self.pipe_name = name
+ self.pipe_write = PipeWriteType.PIPE_READ
+ self.display_level = DispLevel.OPERATOR
+ if name is None:
+ self.read_method_name = None
+ self.write_method_name = None
+ self.is_allowed_name = None
+ else:
+ self.read_method_name = "read_" + name
+ self.write_method_name = "write_" + name
+ self.is_allowed_name = "is_" + name + "_allowed"
+ self.pipe_class = None
+ self.pipe_args = []
+ self.pipe_prop = None
+ if pipe_info is not None:
+ self.from_pipe_info(pipe_info)
+
+ @classmethod
+ def from_dict(cls, pipe_dict):
+ pipe_dict = dict(pipe_dict)
+ name = pipe_dict.pop('name', None)
+ class_name = pipe_dict.pop('class_name', None)
+ self = cls(name, class_name)
+ self.build_from_dict(pipe_dict)
+ return self
+
+ def build_from_dict(self, pipe_dict):
+ self.display_level = pipe_dict.pop('display_level', DispLevel.OPERATOR)
+
+ is_access_explicit = "access" in pipe_dict
+ if is_access_explicit:
+ self.pipe_write = pipe_dict.pop('access')
+ else:
+ # access is defined by which methods were defined
+ r_explicit = "fread" in pipe_dict or "fget" in pipe_dict
+ w_explicit = "fwrite" in pipe_dict or "fset" in pipe_dict
+ if r_explicit and w_explicit:
+ self.pipe_write = PipeWriteType.PIPE_READ_WRITE
+ else:
+ self.pipe_write = PipeWriteType.PIPE_READ
+
+ fread = pipe_dict.pop('fget', pipe_dict.pop('fread', None))
+ if fread is not None:
+ if is_pure_str(fread):
+ self.read_method_name = fread
+ elif inspect.isroutine(fread):
+ self.read_method_name = fread.__name__
+ fwrite = pipe_dict.pop('fset', pipe_dict.pop('fwrite', None))
+ if fwrite is not None:
+ if is_pure_str(fwrite):
+ self.write_method_name = fwrite
+ elif inspect.isroutine(fwrite):
+ self.write_method_name = fwrite.__name__
+ fisallowed = pipe_dict.pop('fisallowed', None)
+ if fisallowed is not None:
+ if is_pure_str(fisallowed):
+ self.is_allowed_name = fisallowed
+ elif inspect.isroutine(fisallowed):
+ self.is_allowed_name = fisallowed.__name__
+ self.pipe_class = pipe_dict.pop("klass", Pipe)
+ self.pipe_args.extend((self.pipe_name, self.display_level, self.pipe_write))
+ if len(pipe_dict):
+ self.pipe_prop = self.__create_user_default_pipe_prop(pipe_dict)
+ return self
+
+ def _set_name(self, name):
+ old_name = self.pipe_name
+ self.pipe_name = name
+ self.pipe_args[0] = name
+ if old_name is None:
+ if self.read_method_name is None:
+ self.read_method_name = "read_" + name
+ if self.write_method_name is None:
+ self.write_method_name = "write_" + name
+ if self.is_allowed_name is None:
+ self.is_allowed_name = "is_" + name + "_allowed"
+
+ def __throw_exception(self, msg, meth="create_pipe()"):
+ Except.throw_exception("PyDs_WrongPipeDefinition", msg, meth)
+
+ def __create_user_default_pipe_prop(self, extra_info):
+ """for internal usage only"""
+ p = UserDefaultPipeProp()
+
+ doc = extra_info.pop('doc', None)
+ if doc is not None:
+ extra_info['description'] = doc
+
+ for k, v in extra_info.items():
+ k_lower = k.lower()
+ method_name = "set_%s" % k_lower.replace(' ','_')
+ if hasattr(p, method_name):
+ method = getattr(p, method_name)
+ method(str(v))
+ else:
+ msg = "Wrong definition of pipe. " \
+ "The object extra information '%s' " \
+ "is not recognized!" % (k,)
+ Except.throw_exception("PyDs_WrongPipeDefinition", msg,
+ "create_user_default_pipe_prop()")
+ return p
+
+ def from_pipe_info(self, pipe_info):
+ name = self.class_name
+ pipe_name = self.pipe_name
+ throw_ex = self.__throw_exception
+ # check for well defined pipe info
+
+ # check parameter
+ if not is_non_str_seq(pipe_info):
+ throw_ex("Wrong data type for value for describing pipe %s in "
+ "class %s\nMust be a sequence with 1 or 2 elements"
+ % (pipe_name, name))
+
+ if len(pipe_info) < 1 or len(pipe_info) > 2:
+ throw_ex("Wrong number of argument for describing pipe %s in "
+ "class %s\nMust be a sequence with 1 or 2 elements"
+ % (pipe_name, name))
+
+ extra_info = {}
+ if len(pipe_info) == 2:
+ # pipe_info[1] must be a dictionary
+ # extra_info = pipe_info[1], with all the keys lowercase
+ for k, v in pipe_info[1].items():
+ extra_info[k.lower()] = v
+
+ pipe_info = pipe_info[0]
+
+ #get write type
+ try:
+ self.pipe_write = PipeWriteType(pipe_info)
+ except:
+ throw_ex("Wrong data write type in pipe argument for "
+ "pipe %s in class %s\nPipe write type must be a "
+ "PyTango.PipeWriteType" % (pipe_name, name))
+ try:
+ self.display_level = DispLevel(extra_info.get("display level",
+ DispLevel.OPERATOR))
+ except:
+ throw_ex("Wrong display level in pipe information for "
+ "pipe %s in class %s\nPipe information for "
+ "display level is not a PyTango.DispLevel"
+ % (pipe_name, name))
+
+ self.pipe_class = extra_info.get("klass", Pipe)
+ self.pipe_args.extend((self.pipe_name, self.display_level, self.pipe_write))
+
+ pipe_prop = None
+ if extra_info:
+ pipe_prop = self.__create_user_default_pipe_prop(extra_info)
+ self.pipe_prop = pipe_prop
+
+ def to_pipe(self):
+ pipe = self.pipe_class(*self.pipe_args)
+ if self.pipe_prop is not None:
+ pipe.set_default_properties(self.pipe_prop)
+ return pipe
diff --git a/src/boost/python/pytango_init.py b/src/boost/python/pytango_init.py
index 8d4fc56..6bdb820 100644
--- a/src/boost/python/pytango_init.py
+++ b/src/boost/python/pytango_init.py
@@ -37,6 +37,7 @@ from .pytango_pprint import pytango_pprint_init
from .pyutil import pyutil_init
from .time_val import time_val_init
from .auto_monitor import auto_monitor_init
+from .pipe import pipe_init
from ._PyTango import constants
from ._PyTango import _get_tango_lib_release
@@ -113,6 +114,7 @@ def init():
pyutil_init(doc=doc)
time_val_init(doc=doc)
auto_monitor_init(doc=doc)
+ pipe_init(doc=doc)
# must come last: depends on device_proxy.init()
attribute_proxy_init(doc=doc)
diff --git a/src/boost/python/server.py b/src/boost/python/server.py
index 8e4a358..cf60482 100644
--- a/src/boost/python/server.py
+++ b/src/boost/python/server.py
@@ -16,7 +16,7 @@ from __future__ import print_function
from __future__ import absolute_import
__all__ = ["DeviceMeta", "Device", "LatestDeviceImpl", "attribute",
- "command", "device_property", "class_property",
+ "command", "pipe", "device_property", "class_property",
"run", "server_run", "Server", "get_worker", "get_gevent_worker"]
import os
@@ -33,16 +33,17 @@ import traceback
from ._PyTango import (CmdArgType, AttrDataFormat, AttrWriteType,
DevFailed, Except, GreenMode, constants,
Database, DbDevInfo, DevState, CmdArgType,
- Attr)
+ Attr, PipeWriteType)
from .attr_data import AttrData
+from .pipe_data import PipeData
from .device_class import DeviceClass
-from .utils import (get_tango_device_classes, is_seq, is_non_str_seq,
+from .utils import (get_latest_device_class, is_seq, is_non_str_seq,
scalar_to_array_type)
from .codec import loads, dumps
API_VERSION = 2
-LatestDeviceImpl = get_tango_device_classes()[-1]
+LatestDeviceImpl = get_latest_device_class()
def __build_to_tango_type():
ret = \
@@ -290,6 +291,128 @@ def __patch_attr_methods(tango_device_klass, attribute):
__patch_write_method(tango_device_klass, attribute)
+def _get_wrapped_pipe_read_method(pipe, read_method):
+ read_args = inspect.getargspec(read_method)
+ nb_args = len(read_args.args)
+
+ green_mode = pipe.read_green_mode
+
+ if nb_args < 2:
+ if green_mode == GreenMode.Synchronous:
+ @functools.wraps(read_method)
+ def read_pipe(self, pipe):
+ ret = read_method(self)
+ if not pipe.get_value_flag() and ret is not None:
+ pipe.set_value(pipe, ret)
+ return ret
+ else:
+ @functools.wraps(read_method)
+ def read_pipe(self, pipe):
+ worker = get_worker()
+ ret = worker.execute(read_method, self)
+ if ret is not None:
+ pipe.set_value(ret)
+ return ret
+ else:
+ if green_mode == GreenMode.Synchronous:
+ read_pipe = read_method
+ else:
+ @functools.wraps(read_method)
+ def read_pipe(self, pipe):
+ return get_worker().execute(read_method, self, pipe)
+
+ return read_pipe
+
+
+def __patch_pipe_read_method(tango_device_klass, pipe):
+ """
+ Checks if method given by it's name for the given DeviceImpl
+ class has the correct signature. If a read/write method doesn't
+ have a parameter (the traditional Pipe), then the method is
+ wrapped into another method which has correct parameter definition
+ to make it work.
+
+ :param tango_device_klass: a DeviceImpl class
+ :type tango_device_klass: class
+ :param pipe: the pipe data information
+ :type pipe: PipeData
+ """
+ read_method = getattr(pipe, "fget", None)
+ if read_method:
+ method_name = "__read_{0}__".format(pipe.pipe_name)
+ pipe.read_method_name = method_name
+ else:
+ method_name = pipe.read_method_name
+ read_method = getattr(tango_device_klass, method_name)
+
+ read_pipe = _get_wrapped_pipe_read_method(pipe, read_method)
+ method_name = "__read_{0}_wrapper__".format(pipe.pipe_name)
+ pipe.read_method_name = method_name
+
+ setattr(tango_device_klass, method_name, read_pipe)
+
+
+def _get_wrapped_pipe_write_method(pipe, write_method):
+ green_mode = pipe.write_green_mode
+
+ if green_mode == GreenMode.Synchronous:
+ @functools.wraps(write_method)
+ def write_pipe(self, pipe):
+ # TODO
+ raise NotImplementedError
+ #value = pipe.get_write_value()
+ return write_method(self, value)
+ else:
+ @functools.wraps(write_method)
+ def write_pipe(self, pipe):
+ raise NotImplementedError
+ #value = pipe.get_write_value()
+ return get_worker().execute(write_method, self, value)
+ return write_pipe
+
+
+def __patch_pipe_write_method(tango_device_klass, pipe):
+ """
+ Checks if method given by it's name for the given DeviceImpl
+ class has the correct signature. If a read/write method doesn't
+ have a parameter (the traditional Pipe), then the method is
+ wrapped into another method which has correct parameter definition
+ to make it work.
+
+ :param tango_device_klass: a DeviceImpl class
+ :type tango_device_klass: class
+ :param pipe: the pipe data information
+ :type pipe: PipeData
+ """
+ write_method = getattr(pipe, "fset", None)
+ if write_method:
+ method_name = "__write_{0}__".format(pipe.pipe_name)
+ pipe.write_method_name = method_name
+ else:
+ method_name = pipe.write_method_name
+ write_method = getattr(tango_device_klass, method_name)
+
+ write_pipe = _get_wrapped_pipe_write_method(pipe, write_method)
+ setattr(tango_device_klass, method_name, write_pipe)
+
+
+def __patch_pipe_methods(tango_device_klass, pipe):
+ """
+ Checks if the read and write methods have the correct signature.
+ If a read/write method doesn't have a parameter (the traditional
+ Pipe), then the method is wrapped into another method to make
+ this work.
+
+ :param tango_device_klass: a DeviceImpl class
+ :type tango_device_klass: class
+ :param pipe: the pipe data information
+ :type pipe: PipeData
+ """
+ __patch_pipe_read_method(tango_device_klass, pipe)
+ if pipe.pipe_write == PipeWriteType.PIPE_READ_WRITE:
+ __patch_pipe_write_method(tango_device_klass, pipe)
+
+
def __patch_init_delete_device(klass):
# TODO allow to force non green mode
green_mode = True
@@ -350,6 +473,7 @@ def __create_tango_deviceclass_klass(tango_device_klass, attrs=None):
attrs = tango_device_klass.__dict__
attr_list = {}
+ pipe_list = {}
class_property_list = {}
device_property_list = {}
cmd_list = {}
@@ -362,6 +486,13 @@ def __create_tango_deviceclass_klass(tango_device_klass, attrs=None):
attr_name = attr_obj.attr_name
attr_list[attr_name] = attr_obj
__patch_attr_methods(tango_device_klass, attr_obj)
+ elif isinstance(attr_obj, pipe):
+ if attr_obj.pipe_name is None:
+ attr_obj._set_name(attr_name)
+ else:
+ attr_name = attr_obj.pipe_name
+ pipe_list[attr_name] = attr_obj
+ __patch_pipe_methods(tango_device_klass, attr_obj)
elif isinstance(attr_obj, device_property):
attr_obj.name = attr_name
device_property_list[attr_name] = [attr_obj.dtype,
@@ -383,7 +514,8 @@ def __create_tango_deviceclass_klass(tango_device_klass, attrs=None):
devclass_attrs = dict(class_property_list=class_property_list,
device_property_list=device_property_list,
- cmd_list=cmd_list, attr_list=attr_list)
+ cmd_list=cmd_list, attr_list=attr_list,
+ pipe_list=pipe_list)
return type(devclass_name, (_DeviceClass,), devclass_attrs)
@@ -741,6 +873,150 @@ class attribute(AttrData):
return type(self)(fget=fget, **self._kwargs)
+class pipe(PipeData):
+ '''
+ Declares a new tango pipe in a :class:`Device`. To be used
+ like the python native :obj:`property` function. For example, to
+ declare a read-only pipe called *ROI* (for Region Of Interest), in a
+ *Detector* :class:`Device` do::
+
+ class Detector(Device):
+ __metaclass__ = DeviceMeta
+
+ ROI = pipe()
+
+ def read_ROI(self):
+ return dict(x=0, y=10, width=100, height=200)
+
+ The same can be achieved with::
+
+ class Detector(Device):
+ __metaclass__ = DeviceMeta
+
+ @pipe
+ def ROI(self):
+ return dict(x=0, y=10, width=100, height=200)
+
+
+ It receives multiple keyword arguments.
+
+ ===================== ================================ ======================================= =======================================================================================
+ parameter type default value description
+ ===================== ================================ ======================================= =======================================================================================
+ name :obj:`str` class member name alternative pipe name
+ display_level :obj:`~PyTango.DispLevel` :obj:`~PyTango.DisLevel.OPERATOR` display level
+ access :obj:`~PyTango.PipeWriteType` :obj:`~PyTango.PipeWriteType.READ` read only/ read write access
+ fget (or fread) :obj:`str` or :obj:`callable` 'read_<pipe_name>' read method name or method object
+ fset (or fwrite) :obj:`str` or :obj:`callable` 'write_<pipe_name>' write method name or method object
+ is_allowed :obj:`str` or :obj:`callable` 'is_<pipe_name>_allowed' is allowed method name or method object
+ label :obj:`str` '<pipe_name>' pipe label
+ doc (or description) :obj:`str` '' pipe description
+ green_mode :obj:`~PyTango.GreenMode` None green mode for read and write. None means use server green mode.
+ read_green_mode :obj:`~PyTango.GreenMode` None green mode for read. None means use server green mode.
+ write_green_mode :obj:`~PyTango.GreenMode` None green mode for write. None means use server green mode.
+ ===================== ================================ ======================================= =======================================================================================
+
+ The same example with a read-write ROI, a customized label and description and::
+
+ class Detector(Device):
+ __metaclass__ = DeviceMeta
+
+ ROI = pipe(label='Region Of Interest', doc='The active region of interest',
+ access=PipeWriteType.PIPE_READ_WRITE)
+
+ def init_device(self):
+ Device.init_device(self)
+ self.__roi = dict(x=0, y=10, width=100, height=200)
+
+ def read_ROI(self):
+ return self.__roi
+
+ def write_ROI(self, roi):
+ self.__roi = dict(roi)
+
+
+ The same, but using pipe as a decorator::
+
+ class Detector(Device):
+ __metaclass__ = DeviceMeta
+
+ def init_device(self):
+ Device.init_device(self)
+ self.__roi = dict(x=0, y=10, width=100, height=200)
+
+ @pipe(label="Region Of Interest")
+ def ROI(self):
+ """The active region of interest"""
+ return self.__roi
+
+ @ROI.write
+ def ROI(self, roi):
+ self.__roi = dict(roi)
+
+ In this second format, defining the `write` / `setter` implicitly sets
+ the pipe access to READ_WRITE.
+
+ .. versionadded:: 9.1.0
+ '''
+
+ def __init__(self, fget=None, **kwargs):
+ self._kwargs = dict(kwargs)
+ name = kwargs.pop("name", None)
+ class_name = kwargs.pop("class_name", None)
+ green_mode = kwargs.pop("green_mode", True)
+ self.read_green_mode = kwargs.pop("read_green_mode", green_mode)
+ self.write_green_mode = kwargs.pop("write_green_mode", green_mode)
+
+ if fget:
+ if inspect.isroutine(fget):
+ self.fget = fget
+ if 'doc' not in kwargs and 'description' not in kwargs:
+ if fget.__doc__ is not None:
+ kwargs['doc'] = fget.__doc__
+ kwargs['fget'] = fget
+
+ super(pipe, self).__init__(name, class_name)
+ self.build_from_dict(kwargs)
+
+ def get_pipe(self, obj):
+ dclass = obj.get_device_class()
+ return dclass.get_pipe_by_name(self.pipe_name)
+
+ # --------------------
+ # descriptor interface
+ # --------------------
+
+ def __get__(self, obj, objtype):
+ return self.get_attribute(obj)
+
+ def __set__(self, obj, value):
+ attr = self.get_attribute(obj)
+ set_complex_value(attr, value)
+
+ def setter(self, fset):
+ """
+ To be used as a decorator. Will define the decorated method
+ as a write pipe method to be called when client writes to the pipe
+ """
+ self.fset = fset
+ if self.attr_write == AttrWriteType.READ:
+ if getattr(self, 'fget', None):
+ self.attr_write = AttrWriteType.READ_WRITE
+ else:
+ self.attr_write = AttrWriteType.WRITE
+ return self
+
+ def write(self, fset):
+ """
+ To be used as a decorator. Will define the decorated method
+ as a write pipe method to be called when client writes to the pipe
+ """
+ return self.setter(fset)
+
+ def __call__(self, fget):
+ return type(self)(fget=fget, **self._kwargs)
+
+
def command(f=None, dtype_in=None, dformat_in=None, doc_in="",
dtype_out=None, dformat_out=None, doc_out="", green_mode=None):
"""
diff --git a/src/boost/python/utils.py b/src/boost/python/utils.py
index cc71a0a..62051ac 100644
--- a/src/boost/python/utils.py
+++ b/src/boost/python/utils.py
@@ -38,7 +38,7 @@ import collections
from ._PyTango import StdStringVector, StdDoubleVector, \
DbData, DbDevInfos, DbDevExportInfos, CmdArgType, AttrDataFormat, \
EventData, AttrConfEventData, DataReadyEventData, DevFailed, constants, \
- GreenMode
+ GreenMode, DevState
from .constants import AlrmValueNotSpec, StatusNotSet, TgLibVers
from .release import Release
@@ -75,6 +75,78 @@ _array_types = _array_numerical_types + _array_bool_types + _array_str_types + \
_binary_types = (CmdArgType.DevEncoded, CmdArgType.DevVarCharArray)
+def __build_to_tango_type():
+ ret = \
+ {
+ int : CmdArgType.DevLong64,
+ str : CmdArgType.DevString,
+ bool : CmdArgType.DevBoolean,
+ bytearray : CmdArgType.DevEncoded,
+ float : CmdArgType.DevDouble,
+ chr : CmdArgType.DevUChar,
+ None : CmdArgType.DevVoid,
+
+ 'int' : CmdArgType.DevLong,
+ 'int16' : CmdArgType.DevShort,
+ 'int32' : CmdArgType.DevLong,
+ 'int64' : CmdArgType.DevLong64,
+ 'uint' : CmdArgType.DevULong,
+ 'uint16' : CmdArgType.DevUShort,
+ 'uint32' : CmdArgType.DevULong,
+ 'uint64' : CmdArgType.DevULong64,
+ 'str' : CmdArgType.DevString,
+ 'string' : CmdArgType.DevString,
+ 'text' : CmdArgType.DevString,
+ 'bool' : CmdArgType.DevBoolean,
+ 'boolean' : CmdArgType.DevBoolean,
+ 'bytes' : CmdArgType.DevEncoded,
+ 'bytearray' : CmdArgType.DevEncoded,
+ 'float' : CmdArgType.DevDouble,
+ 'float32' : CmdArgType.DevFloat,
+ 'float64' : CmdArgType.DevDouble,
+ 'double' : CmdArgType.DevDouble,
+ 'byte' : CmdArgType.DevUChar,
+ 'chr' : CmdArgType.DevUChar,
+ 'char' : CmdArgType.DevUChar,
+ 'None' : CmdArgType.DevVoid,
+ 'state' : CmdArgType.DevState,
+ 'enum' : CmdArgType.DevEnum,
+ 'blob' : CmdArgType.DevPipeBlob,
+ }
+
+ try:
+ ret[long] = ret[int]
+ except NameError:
+ pass
+
+
+ for key in dir(CmdArgType):
+ if key.startswith("Dev"):
+ value = getattr(CmdArgType, key)
+ ret[key] = ret[value] = value
+
+ if constants.NUMPY_SUPPORT:
+ import numpy
+ FROM_TANGO_TO_NUMPY_TYPE = { \
+ CmdArgType.DevBoolean : numpy.bool8,
+ CmdArgType.DevUChar : numpy.ubyte,
+ CmdArgType.DevShort : numpy.short,
+ CmdArgType.DevUShort : numpy.ushort,
+ CmdArgType.DevLong : numpy.int32,
+ CmdArgType.DevULong : numpy.uint32,
+ CmdArgType.DevLong64 : numpy.int64,
+ CmdArgType.DevULong64 : numpy.uint64,
+ CmdArgType.DevString : numpy.str,
+ CmdArgType.DevDouble : numpy.float64,
+ CmdArgType.DevFloat : numpy.float32,
+ }
+
+ for key, value in FROM_TANGO_TO_NUMPY_TYPE.items():
+ ret[value] = key
+ return ret
+
+TO_TANGO_TYPE = __build_to_tango_type()
+
_scalar_to_array_type = {
CmdArgType.DevBoolean : CmdArgType.DevVarBooleanArray,
CmdArgType.DevUChar : CmdArgType.DevVarCharArray,
@@ -91,6 +163,12 @@ _scalar_to_array_type = {
CmdArgType.ConstDevString : CmdArgType.DevVarStringArray,
}
+# add derived scalar types to scalar to array map
+for k, v in TO_TANGO_TYPE.items():
+ if v in _scalar_to_array_type:
+ _scalar_to_array_type[k] = _scalar_to_array_type[v]
+
+
__NO_STR_VALUE = AlrmValueNotSpec, StatusNotSet
__device_classes = None
@@ -101,7 +179,7 @@ bool_ = lambda value_str : value_str.lower() == "true"
def __import(name):
__import__(name)
return sys.modules[name]
-
+
def __requires(package_name, min_version=None, conflicts=(),
software_name="Software"):
from distutils.version import LooseVersion
@@ -222,6 +300,11 @@ def get_tango_device_classes():
break
return __device_classes
+
+def get_latest_device_class():
+ return get_tango_device_classes()[-1]
+
+
try:
__str_klasses = basestring,
except NameError:
@@ -260,6 +343,43 @@ __number_klasses = tuple(__number_klasses)
__seq_klasses = tuple(__seq_klasses)
+def __get_tango_type(obj):
+ from .device_server import DataElement
+ if is_non_str_seq(obj):
+ tg_type, tg_format = get_tango_type(obj[0])
+ tg_format = AttrDataFormat(int(tg_format)+1)
+ return tg_type, tg_format
+ elif is_pure_str(obj):
+ r = CmdArgType.DevString
+ elif isinstance(obj, DevState):
+ r = CmdArgType.DevState
+ elif isinstance(obj, bool):
+ r = CmdArgType.DevBoolean
+ elif isinstance(obj, __int_klasses):
+ r = CmdArgType.DevLong64
+ elif isinstance(obj, __number_klasses):
+ r = CmdArgType.DevDouble
+ return r, AttrDataFormat.SCALAR
+
+
+def __get_tango_type_numpy_support(obj):
+ import numpy
+ try:
+ ndim, dtype = obj.ndim, str(obj.dtype)
+ if ndim > 2:
+ raise TypeError('cannot translate numpy array with {0} '
+ 'dimensions to tango type'.format(obj.ndim))
+ return TO_TANGO_TYPE[dtype], AttrDataFormat(ndim)
+ except AttributeError:
+ return __get_tango_type(obj)
+
+
+def get_tango_type(obj):
+ if constants.NUMPY_SUPPORT:
+ return __get_tango_type_numpy_support(obj)
+ return __get_tango_type(obj)
+
+
def is_pure_str(obj):
"""
Tells if the given object is a python string.
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/pytango.git
More information about the debian-science-commits
mailing list