[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