[pytango] 01/483: Move PyTango directory to bindings

Sandor Bodo-Merle sbodomerle-guest at moszumanska.debian.org
Thu Sep 28 19:14:18 UTC 2017


This is an automated email from the git hooks/post-receive script.

sbodomerle-guest pushed a commit to annotated tag bliss_8.10
in repository pytango.

commit 2df221351c40c9562b376721bd4e8896fc2cd4dc
Author: taurel <taurel at 4e9c00fd-8f2e-0410-aa12-93ce3db5e235>
Date:   Tue Feb 22 09:29:57 2011 +0000

    Move PyTango directory to bindings
    
    git-svn-id: http://svn.code.sf.net/p/tango-cs/code/bindings/PyTango/trunk@15665 4e9c00fd-8f2e-0410-aa12-93ce3db5e235
---
 MANIFEST.in                                   |   12 +
 PyTango/__init__.py                           |   69 +
 PyTango/api_util.py                           |  145 ++
 PyTango/attribute_proxy.py                    |  361 ++++
 PyTango/base_types.py                         |  620 +++++++
 PyTango/callback.py                           |   82 +
 PyTango/connection.py                         |  546 ++++++
 PyTango/db.py                                 | 2053 +++++++++++++++++++++++
 PyTango/device_attribute.py                   |  118 ++
 PyTango/device_class.py                       |  910 ++++++++++
 PyTango/device_data.py                        |   94 ++
 PyTango/device_proxy.py                       | 1692 +++++++++++++++++++
 PyTango/device_server.py                      | 2202 +++++++++++++++++++++++++
 PyTango/globals.py                            |  119 ++
 PyTango/group.py                              |  219 +++
 PyTango/group_element.py                      |  586 +++++++
 PyTango/group_reply.py                        |  114 ++
 PyTango/group_reply_list.py                   |   98 ++
 PyTango/ipython/__init__.py                   |   25 +
 PyTango/ipython/ipy_cli.py                    |   82 +
 PyTango/ipython/ipy_install.py                |  103 ++
 PyTango/ipython/ipy_qt.py                     |  387 +++++
 PyTango/ipython/ipython.py                    |   64 +
 PyTango/ipython/ipython_00_10.py              |  978 +++++++++++
 PyTango/log4tango.py                          |  284 ++++
 PyTango/pytango_init.py                       |   81 +
 PyTango/pytango_pprint.py                     |  143 ++
 PyTango/pyutil.py                             |  670 ++++++++
 PyTango/release.py                            |   61 +
 PyTango/tango_numpy.py                        |  151 ++
 PyTango/time_val.py                           |  196 +++
 PyTango/utils.py                              |  648 ++++++++
 PyTango3/__init__.py                          |   23 +
 PyTango3/tango3.py                            |  155 ++
 cPyTango/__init__.py                          |    1 +
 cPyTango/cPyTango.py                          |  873 ++++++++++
 cPyTango/enumeration.py                       |   86 +
 doc/WINDOWS-COMPILATION-EXAMPLE.TXT           |   38 +
 doc/_templates/layout.html                    |   10 +
 doc/api.rst                                   |   16 +
 doc/client/attribute_proxy.rst                |   11 +
 doc/client/device_proxy.rst                   |    9 +
 doc/client/group.rst                          |   46 +
 doc/client/index.rst                          |   11 +
 doc/client/miscellaneous.rst                  |  144 ++
 doc/client/other.rst                          |   60 +
 doc/conf.py                                   |  495 ++++++
 doc/contents.rst                              |   21 +
 doc/database.rst                              |   29 +
 doc/exception.rst                             |  317 ++++
 doc/faq.rst                                   |  364 ++++
 doc/index.rst                                 |   61 +
 doc/logo-medium.png                           |  Bin 0 -> 39356 bytes
 doc/logo.png                                  |  Bin 0 -> 17765 bytes
 doc/quicktour.rst                             |  531 ++++++
 doc/quicktour_old.rst                         |  439 +++++
 doc/revision.rst                              |  160 ++
 doc/server/attribute.rst                      |   34 +
 doc/server/device.rst                         |   41 +
 doc/server/device_class.rst                   |    7 +
 doc/server/index.rst                          |  877 ++++++++++
 doc/server/logging.rst                        |   40 +
 doc/server/util.rst                           |    8 +
 doc/sphinxext/ipython_console_highlighting.py |  114 ++
 doc/sphinxext/spock_console_highlighting.py   |  116 ++
 doc/spock/features.rst                        |   40 +
 doc/spock/highlights.rst                      |  577 +++++++
 doc/spock/index.rst                           |   46 +
 doc/spock/spock00.png                         |  Bin 0 -> 22628 bytes
 doc/spock/spock01.png                         |  Bin 0 -> 74424 bytes
 doc/spock/spock02.png                         |  Bin 0 -> 55182 bytes
 doc/spock/spock03.png                         |  Bin 0 -> 17471 bytes
 doc/spock/spock04.png                         |  Bin 0 -> 87205 bytes
 doc/start.rst                                 |  250 +++
 doc/title.png                                 |  Bin 0 -> 80394 bytes
 ez_setup.py                                   |  284 ++++
 images/logo-2009.xcf                          |  Bin 0 -> 3059144 bytes
 images/logo-2010.png                          |  Bin 0 -> 1363560 bytes
 images/logo-medium-2009.png                   |  Bin 0 -> 39356 bytes
 images/logo-medium-2010.png                   |  Bin 0 -> 98513 bytes
 images/logo-small-2009.png                    |  Bin 0 -> 17765 bytes
 setup.py                                      |  399 +++++
 src/api_util.cpp                              |   54 +
 src/archive_event_info.cpp                    |   36 +
 src/attr_conf_event_data.cpp                  |   51 +
 src/attribute_alarm_info.cpp                  |   40 +
 src/attribute_dimension.cpp                   |   35 +
 src/attribute_event_info.cpp                  |   36 +
 src/attribute_info.cpp                        |   35 +
 src/attribute_info_ex.cpp                     |   37 +
 src/attribute_proxy.cpp                       |  124 ++
 src/base_types.cpp                            |  345 ++++
 src/base_types_numpy.hpp                      |  131 ++
 src/callback.cpp                              |  386 +++++
 src/callback.h                                |  106 ++
 src/change_event_info.cpp                     |   36 +
 src/command_info.cpp                          |   34 +
 src/connection.cpp                            |  196 +++
 src/constants.cpp                             |  179 ++
 src/data_ready_event_data.cpp                 |   60 +
 src/database.cpp                              |  457 +++++
 src/db.cpp                                    |   90 +
 src/defs.h                                    |   43 +
 src/dev_command_info.cpp                      |   43 +
 src/dev_error.cpp                             |   50 +
 src/device_attribute.cpp                      |  656 ++++++++
 src/device_attribute.h                        |  159 ++
 src/device_attribute_config.cpp               |   51 +
 src/device_attribute_history.cpp              |   40 +
 src/device_attribute_numpy.hpp                |  265 +++
 src/device_data.cpp                           |  211 +++
 src/device_data_history.cpp                   |   43 +
 src/device_info.cpp                           |   46 +
 src/device_proxy.cpp                          |  753 +++++++++
 src/enums.cpp                                 |  230 +++
 src/event_data.cpp                            |   59 +
 src/exception.cpp                             |  484 ++++++
 src/exception.h                               |  104 ++
 src/fast_from_py.h                            |  705 ++++++++
 src/fast_from_py_numpy.hpp                    |  265 +++
 src/from_py.cpp                               |  316 ++++
 src/from_py.h                                 |  259 +++
 src/group.cpp                                 |  116 ++
 src/group_element.cpp                         |  294 ++++
 src/group_reply.cpp                           |   85 +
 src/group_reply_list.cpp                      |   69 +
 src/locker_info.cpp                           |   56 +
 src/locking_thread.cpp                        |   33 +
 src/periodic_event_info.cpp                   |   40 +
 src/poll_device.cpp                           |   40 +
 src/precompiled_header.hpp                    |   32 +
 src/pytango.cpp                               |  118 ++
 src/pytgutils.cpp                             |   31 +
 src/pytgutils.h                               |   83 +
 src/pyutils.cpp                               |   66 +
 src/pyutils.h                                 |  127 ++
 src/server/attr.cpp                           |  143 ++
 src/server/attr.h                             |  429 +++++
 src/server/attribute.cpp                      |  461 ++++++
 src/server/attribute.h                        |   33 +
 src/server/command.cpp                        |  248 +++
 src/server/command.h                          |   33 +
 src/server/device_class.cpp                   |  289 ++++
 src/server/device_class.h                     |  175 ++
 src/server/device_impl.cpp                    | 1294 +++++++++++++++
 src/server/device_impl.h                      |  428 +++++
 src/server/dserver.cpp                        |  181 ++
 src/server/log4tango.cpp                      |  123 ++
 src/server/multi_attribute.cpp                |   34 +
 src/server/subdev.cpp                         |   37 +
 src/server/tango_util.cpp                     |  260 +++
 src/server/user_default_attr_prop.cpp         |   32 +
 src/server/wattribute.cpp                     |  562 +++++++
 src/server/wattribute_numpy.hpp               |   64 +
 src/tango_numpy.h                             |   97 ++
 src/tgutils.h                                 |  250 +++
 src/time_val.cpp                              |   36 +
 src/to_py.cpp                                 |  214 +++
 src/to_py.h                                   |  314 ++++
 src/to_py_numpy.hpp                           |   96 ++
 src/version.cpp                               |   32 +
 161 files changed, 34951 insertions(+)

diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..07def70
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,12 @@
+recursive-include PyTango *.py
+recursive-include PyTango3 *.py
+graft src
+graft doc
+graft build/sphinx/html
+
+global-exclude *.pyc
+exclude setup.cfg
+exclude .project
+exclude .pydevproject
+exclude images/*
+exclude src/precompiled_header.hpp.gch
\ No newline at end of file
diff --git a/PyTango/__init__.py b/PyTango/__init__.py
new file mode 100644
index 0000000..e61ac2d
--- /dev/null
+++ b/PyTango/__init__.py
@@ -0,0 +1,69 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is the main PyTango package file.
+Documentation for this package can be found online:
+
+http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+"""
+
+__docformat__ = "restructuredtext"
+
+try:
+    import time
+    from _PyTango import *
+except ImportError, ie:
+    if not ie.args[0].count("_PyTango"):
+        raise ie
+    print 80*"-"
+    print ie
+    print 80*"-"
+    print "Probably your current directory is the PyTango's source installation directory."
+    print "You must leave this directory first before using PyTango, otherwise the"
+    print "source distribution will conflict with the installed PyTango"
+    print 80*"-"
+    import sys
+    sys.exit(1)
+
+ArgType = _PyTango.CmdArgType
+
+from release import *
+
+__author__ = "\n".join([ "%s <%s>" % x for x in Release.authors.values()])
+__version_info__ = Release.version_info
+__version__ = Release.version
+__version_long__ = Release.version_long
+__version_number__ = Release.version_number
+__version_description__  = Release.version_description
+__doc__ = Release.long_description
+
+import pytango_init
+from log4tango import *
+from device_server import *
+from attribute_proxy import *
+from group import *
+from pyutil import *
+from device_class import *
+from globals import *
+from utils import *
+from tango_numpy import *
diff --git a/PyTango/api_util.py b/PyTango/api_util.py
new file mode 100644
index 0000000..463d1f3
--- /dev/null
+++ b/PyTango/api_util.py
@@ -0,0 +1,145 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = []
+
+__docformat__ = "restructuredtext"
+
+from _PyTango import ApiUtil
+
+from utils import document_method, document_static_method
+
+def __init_api_util():
+    pass
+
+def __doc_api_util():
+    
+    ApiUtil.__doc__ = """
+    This class allows you to access the tango syncronization model API.
+    It is designed as a singleton. To get a reference to the singleton object
+    you must do::
+    
+        import PyTango
+        apiutil = PyTango.ApiUtil.instance()
+        
+    .. versionadded:: 7.1.3"""
+    
+    document_static_method(ApiUtil, "instance", """
+    instance() -> ApiUtil
+
+            Returns the ApiUtil singleton instance.
+
+        Parameters : None
+        Return     : (ApiUtil) a reference to the ApiUtil singleton object.
+
+        .. versionadded:: 7.1.3
+    """ )
+
+    document_method(ApiUtil, "pending_asynch_call", """
+    pending_asynch_call(self, req) -> int
+
+            Return number of asynchronous pending requests (any device). 
+            The input parameter is an enumeration with three values which are:
+            
+                - POLLING: Return only polling model asynchronous request number
+                - CALL_BACK: Return only callback model asynchronous request number
+                - ALL_ASYNCH: Return all asynchronous request number
+
+        Parameters :
+            - req : (asyn_req_type) asynchronous request type
+            
+        Return     : (int) the number of pending requests for the given type
+
+        .. versionadded:: 7.1.3
+    """ )
+    
+    document_method(ApiUtil, "get_asynch_replies", """
+    get_asynch_replies(self) -> None
+
+            Fire callback methods for all (any device) asynchronous requests 
+            (command and attribute) with already arrived replied. Returns 
+            immediately if there is no replies already arrived or if there is 
+            no asynchronous requests. 
+
+        Parameters : None
+        Return     : None
+
+        Throws     : None, all errors are reported using the err and errors fields
+        of the parameter passed to the callback method.
+        
+        .. versionadded:: 7.1.3
+        
+    get_asynch_replies(self) -> None
+
+            Fire callback methods for all (any device) asynchronous requests
+            (command and attributes) with already arrived replied. Wait and
+            block the caller for timeout milliseconds if they are some
+            device asynchronous requests which are not yet arrived.
+            Returns immediately if there is no asynchronous request.
+            If timeout is set to 0, the call waits until all the asynchronous
+            requests sent has received a reply.
+
+        Parameters :
+            - timeout : (int) timeout (milliseconds)
+        Return     : None
+        
+        Throws     : AsynReplyNotArrived. All other errors are reported using 
+        the err and errors fields of the object passed to the callback methods.
+        
+        .. versionadded:: 7.1.3
+    """ )
+
+    document_method(ApiUtil, "set_asynch_cb_sub_model", """
+    set_asynch_cb_sub_model(self, model) -> None
+
+            Set the asynchronous callback sub-model between the pull and push sub-model.
+            The cb_sub_model data type is an enumeration with two values which are:
+            
+                - PUSH_CALLBACK: The push sub-model
+                - PULL_CALLBACK: The pull sub-model
+
+        Parameters :
+            - model : (cb_sub_model) the callback sub-model
+        Return     : None
+
+        .. versionadded:: 7.1.3
+    """ )
+
+    document_method(ApiUtil, "get_asynch_cb_sub_model", """
+    get_asynch_cb_sub_model(self) -> cb_sub_model
+
+            Get the asynchronous callback sub-model.
+
+        Parameters : None
+        Return     : (cb_sub_model) the active asynchronous callback sub-model.
+
+        .. versionadded:: 7.1.3
+    """ )
+
+def init(doc=True):
+    __init_api_util()
+    if doc:
+        __doc_api_util()
\ No newline at end of file
diff --git a/PyTango/attribute_proxy.py b/PyTango/attribute_proxy.py
new file mode 100644
index 0000000..e871750
--- /dev/null
+++ b/PyTango/attribute_proxy.py
@@ -0,0 +1,361 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module. It completes the binding of
+:class:`PyTango.AttributeProxy`.
+
+To access these members use directly :mod:`PyTango` module and NOT 
+PyTango.attribute_proxy.
+"""
+
+__all__ = [ "AttributeProxy" ]
+            
+__docformat__ = "restructuredtext"
+
+import operator
+import types
+
+from _PyTango import StdStringVector
+from _PyTango import DbData, DbDatum
+from PyTango.utils import seq_2_StdStringVector, StdStringVector_2_seq
+from PyTango.utils import seq_2_DbData, DbData_2_dict
+from utils import document_method as __document_method
+
+from _PyTango import    __AttributeProxy as _AttributeProxy,         \
+                        DeviceProxy
+
+def __AttributeProxy__get_property(self, propname, value=None):
+    """
+    get_property(self, propname, value) -> DbData
+    
+            Get a (list) property(ies) for an attribute.
+
+            This method accepts the following types as propname parameter:
+            1. string [in] - single property data to be fetched
+            2. sequence<string> [in] - several property data to be fetched
+            3. PyTango.DbDatum [in] - single property data to be fetched
+            4. PyTango.DbData [in,out] - several property data to be fetched.
+            5. sequence<DbDatum> - several property data to be feteched
+
+            Note: for cases 3, 4 and 5 the 'value' parameter if given, is IGNORED.
+
+            If value is given it must be a PyTango.DbData that will be filled with the
+            property values
+
+        Parameters :
+            - propname : (str) property(ies) name(s)
+            - value : (PyTango.DbData) (optional, default is None meaning that the
+                      method will create internally a PyTango.DbData and return
+                      it filled with the property values
+
+        Return     : (DbData) containing the property(ies) value(s). If a
+                     PyTango.DbData is given as parameter, it returns the same
+                     object otherwise a new PyTango.DbData is returned
+
+        Throws     : NonDbDevice, ConnectionFailed (with database),
+                     CommunicationFailed (with database),
+                     DevFailed from database device
+    """
+
+    if type(propname) in types.StringTypes or isinstance(propname, StdStringVector):
+        new_value = value
+        if new_value is None:
+            new_value = DbData()
+        self._get_property(propname, new_value)
+        return DbData_2_dict(new_value)
+    elif isinstance(propname, DbDatum):
+        new_value = DbData()
+        new_value.append(propname)
+        self._get_property(new_value)
+        return DbData_2_dict(new_value)
+    elif operator.isSequenceType(propname):
+        if isinstance(propname, DbData):
+            self._get_property(propname)
+            return DbData_2_dict(propname)
+
+        if type(propname[0]) in types.StringTypes:
+            new_propname = StdStringVector()
+            for i in propname: new_propname.append(i)
+            new_value = value
+            if new_value is None:
+                new_value = DbData()
+            self._get_property(new_propname, new_value)
+            return DbData_2_dict(new_value)
+        elif isinstance(propname[0], DbDatum):
+            new_value = DbData()
+            for i in propname: new_value.append(i)
+            self._get_property(new_value)
+            return DbData_2_dict(new_value)
+
+def __AttributeProxy__put_property(self, value):
+    """
+    put_property(self, value) -> None
+    
+            Insert or update a list of properties for this attribute.
+            This method accepts the following types as value parameter:
+            1. PyTango.DbDatum - single property data to be inserted
+            2. PyTango.DbData - several property data to be inserted
+            3. sequence<DbDatum> - several property data to be inserted
+            4. dict<str, DbDatum> - keys are property names and value has data to be inserted
+            5. dict<str, seq<str>> - keys are property names and value has data to be inserted
+            6. dict<str, obj> - keys are property names and str(obj) is property value
+
+        Parameters :
+            - value : can be one of the following:
+                1. PyTango.DbDatum - single property data to be inserted
+                2. PyTango.DbData - several property data to be inserted
+                3. sequence<DbDatum> - several property data to be inserted
+                4. dict<str, DbDatum> - keys are property names and value has data to be inserted
+                5. dict<str, seq<str>> - keys are property names and value has data to be inserted
+                6. dict<str, obj> - keys are property names and str(obj) is property value
+
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed
+                    DevFailed from device (DB_SQLError)
+    """
+    if isinstance(value, DbData):
+        pass
+    elif isinstance(value, DbDatum):
+        new_value = DbData()
+        new_value.append(value)
+        value = new_value
+    elif operator.isSequenceType(value) and not type(value) in types.StringTypes:
+        new_value = seq_2_DbData(value)
+    elif operator.isMappingType(value):
+        new_value = DbData()
+        for k, v in value.iteritems():
+            if isinstance(v, DbDatum):
+                new_value.append(v)
+                continue
+            db_datum = DbDatum(k)
+            if operator.isSequenceType(v) and not type(v) in types.StringTypes:
+                seq_2_StdStringVector(v, db_datum.value_string)
+            else:
+                db_datum.value_string.append(str(v))
+            new_value.append(db_datum)
+        value = new_value
+    else:
+        raise TypeError('value must be a PyTango.DbDatum, PyTango.DbData,'\
+                        'a sequence<DbDatum> or a dictionary')
+    return self._put_property(value)
+
+def __AttributeProxy__delete_property(self, value):
+    """
+    delete_property(self, value) -> None
+    
+            Delete a the given of properties for this attribute.
+            This method accepts the following types as value parameter:
+            1. string [in] - single property to be deleted
+            2. PyTango.DbDatum [in] - single property data to be deleted
+            3. PyTango.DbData [in] - several property data to be deleted
+            4. sequence<string> [in]- several property data to be deleted
+            5. sequence<DbDatum> [in] - several property data to be deleted
+            6. dict<str, obj> [in] - keys are property names to be deleted (values are ignored)
+            7. dict<str, DbDatum> [in] - several DbDatum.name are property names to be
+                                        deleted (keys are ignored)
+
+        Parameters :
+            - value : can be one of the following:
+                1. string [in] - single property data to be deleted
+                2. PyTango.DbDatum [in] - single property data to be deleted
+                3. PyTango.DbData [in] - several property data to be deleted
+                4. sequence<string> [in]- several property data to be deleted
+                5. sequence<DbDatum> [in] - several property data to be deleted
+                6. dict<str, obj> [in] - keys are property names to be deleted (values are ignored)
+                7. dict<str, DbDatum> [in] - several DbDatum.name are property names
+                                            to be deleted (keys are ignored)
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed
+                    DevFailed from device (DB_SQLError)
+    """
+    if isinstance(value, DbData) or isinstance(value, StdStringVector) or \
+       type(value) in types.StringTypes:
+        new_value = value
+    elif isinstance(value, DbDatum):
+        new_value = DbData()
+        new_value.append(value)
+    elif operator.isSequenceType(value):
+        new_value = DbData()
+        for e in value:
+            if isinstance(e, DbDatum):
+                new_value.append(e)
+            else:
+                new_value.append(DbDatum(str(e)))
+    elif operator.isMappingType(value):
+        new_value = DbData()
+        for k, v in value.iteritems():
+            if isinstance(v, DbDatum):
+                new_value.append(v)
+            else:
+                new_value.append(DbDatum(k))
+    else:
+        raise TypeError('value must be a string, PyTango.DbDatum, '\
+                        'PyTango.DbData, a sequence or a dictionary')
+
+    return self._delete_property(new_value)
+
+# It is easier to reimplement AttributeProxy in python using DeviceProxy than
+# wrapping C++ AttributeProxy. However I still rely in the original
+# AttributeProxy for the constructor (parsing strings if necessary) and some
+# other things. With the _method_* functions defined later it is really easy.
+# One reason to do it this way: get_device_proxy() will always return the
+# same PyTango.DeviceProxy with this implementation. And then we can trust
+# it's automatic event unsubscription to handle events.
+class AttributeProxy(object):
+    """
+        AttributeProxy is the high level Tango object which provides the
+        client with an easy-to-use interface to TANGO attributes.
+        
+        To create an AttributeProxy, a complete attribute name must be set
+        in the object constructor.
+        
+        Example:
+            att = AttributeProxy("tango/tangotest/1/long_scalar")
+
+        Note: PyTango implementation of AttributeProxy is in part a
+        python reimplementation of the AttributeProxy found on the C++ API.
+    """
+    def __init__(self, *args, **kwds):
+        self.__attr_proxy = _AttributeProxy(*args, **kwds)
+        # get_device_proxy() returns a different python object each time
+        # we don't want a different object, so we save the current one.
+        self.__dev_proxy = self.__attr_proxy.get_device_proxy()
+
+    def get_device_proxy(self):
+        """
+        get_device_proxy(self) -> DeviceProxy
+        
+                A method which returns the device associated to the attribute
+        
+            Parameters : None
+            
+            Return     : (DeviceProxy)
+        """
+        return self.__dev_proxy
+
+    def name(self):
+        """
+        name(self) -> str
+            
+                Returns the attribute name
+                
+            Parameters : None
+            Return     : (str) with the attribute name
+        """
+        return self.__attr_proxy.name()
+
+    def __str__(self):
+        return "AttributeProxy(%s)" % self.name()
+
+    def __repr__(self):
+        return "AttributeProxy(%s)" % self.name()
+
+def _method_dev_and_name(dp_fn_name, doc=True):
+    def __new_fn(self, *args, **kwds):
+        return getattr(self._AttributeProxy__dev_proxy, dp_fn_name)(self.name(), *args, **kwds)
+    if doc:
+        __new_fn.__doc__ =  "This method is a simple way to do:\n" + \
+                            "\tself.get_device_proxy()."+dp_fn_name+ \
+                            "(self.name(), ...)\n\n" + \
+                            "For convenience, here is the documentation of DeviceProxy." + \
+                            dp_fn_name + "(...):\n" + \
+                            str(getattr(DeviceProxy, dp_fn_name).__doc__)
+    __new_fn.__name__ = dp_fn_name
+    return __new_fn
+
+def _method_device(dp_fn_name, doc=True):
+    def __new_fn(self, *args, **kwds):
+        return getattr(self._AttributeProxy__dev_proxy, dp_fn_name)(*args, **kwds)
+    if doc:
+        __new_fn.__doc__ =  "This method is a simple way to do:\n" + \
+                            "\tself.get_device_proxy()."+dp_fn_name+ \
+                            "(...)\n\n" + \
+                            "For convenience, here is the documentation of DeviceProxy." + \
+                            dp_fn_name + "(...):\n" + \
+                            str(getattr(DeviceProxy, dp_fn_name).__doc__)
+    __new_fn.__name__ = dp_fn_name
+    return __new_fn
+
+def _method_attribute(dp_fn_name, doc=True):
+    def __new_fn(self, *args, **kwds):
+        return getattr(self._AttributeProxy__attr_proxy, dp_fn_name)(*args, **kwds)
+    if doc:
+        __new_fn.__doc__ =  getattr(_AttributeProxy, dp_fn_name).__doc__
+    __new_fn.__name__ = dp_fn_name
+    return __new_fn
+
+def __init_AttributeProxy(doc=True):
+
+    _AttributeProxy.get_property        = __AttributeProxy__get_property
+    _AttributeProxy.put_property        = __AttributeProxy__put_property
+    _AttributeProxy.delete_property     = __AttributeProxy__delete_property
+
+    # General methods
+    #AttributeProxy.name                manually defined
+    AttributeProxy.status               = _method_device('status', doc=doc)
+    AttributeProxy.state                = _method_device('state', doc=doc)
+    AttributeProxy.ping                 = _method_device('ping', doc=doc)
+    AttributeProxy.get_transparency_reconnection=_method_device('get_transparency_reconnection', doc=doc)
+    AttributeProxy.set_transparency_reconnection=_method_device('set_transparency_reconnection', doc=doc)
+
+    # Property methods
+    AttributeProxy.get_property         = _method_attribute('get_property', doc=doc)
+    AttributeProxy.put_property         = _method_attribute('put_property', doc=doc)
+    AttributeProxy.delete_property      = _method_attribute('delete_property', doc=doc)
+
+    # Attribute methods
+    AttributeProxy.get_config           = _method_dev_and_name('get_attribute_config', doc=doc)
+    AttributeProxy.set_config           = _method_device('set_attribute_config', doc=doc)
+
+    AttributeProxy.write                = _method_dev_and_name('write_attribute', doc=doc)
+    AttributeProxy.read                 = _method_dev_and_name('read_attribute', doc=doc)
+    AttributeProxy.write_read           = _method_dev_and_name('write_read_attribute', doc=doc)
+
+    # History methods...
+    AttributeProxy.history              = _method_dev_and_name('attribute_history', doc=doc)
+
+    # Polling administration methods
+    AttributeProxy.poll                 = _method_dev_and_name('poll_attribute', doc=doc)
+    AttributeProxy.get_poll_period      = _method_dev_and_name('get_attribute_poll_period', doc=doc)
+    AttributeProxy.is_polled            = _method_dev_and_name('is_attribute_polled', doc=doc)
+    AttributeProxy.stop_poll            = _method_dev_and_name('stop_poll_attribute', doc=doc)
+
+    # Asynchronous methods
+    AttributeProxy.read_asynch          = _method_dev_and_name('read_attribute_asynch', doc=doc)
+    AttributeProxy.read_reply           = _method_device('read_attribute_reply', doc=doc)
+    AttributeProxy.write_asynch         = _method_device('write_attribute_asynch', doc=doc)
+    AttributeProxy.write_reply          = _method_device('write_attribute_reply', doc=doc)
+
+    # Event methods
+    AttributeProxy.subscribe_event      = _method_dev_and_name('subscribe_event', doc=doc)
+    AttributeProxy.unsubscribe_event    = _method_device('unsubscribe_event', doc=doc)
+
+    AttributeProxy.get_events           = _method_device('get_events', doc=doc)
+    AttributeProxy.event_queue_size     = _method_device('event_queue_size', doc=doc)
+    AttributeProxy.get_last_event_date  = _method_device('get_last_event_date', doc=doc)
+    AttributeProxy.is_event_queue_empty = _method_device('is_event_queue_empty', doc=doc)
+
+def init(doc=True):
+    __init_AttributeProxy(doc=doc)
diff --git a/PyTango/base_types.py b/PyTango/base_types.py
new file mode 100644
index 0000000..67aaeb8
--- /dev/null
+++ b/PyTango/base_types.py
@@ -0,0 +1,620 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = []
+
+__docformat__ = "restructuredtext"
+
+import operator
+
+from _PyTango import *
+from utils import document_method, document_static_method
+from utils import document_enum as __document_enum
+
+def __StdVector__add(self, seq):
+    ret = seq.__class__(self)
+    ret.extend(seq)
+    return ret
+
+def __StdVector__mul(self, n):
+    ret = self.__class__()
+    for _ in xrange(n):
+        ret.extend(self)
+    return ret
+
+def __StdVector__imul(self, n):
+    ret = self.__class__()
+    for _ in xrange(n):
+        ret.extend(self)
+    return ret
+
+def __StdVector__getitem(self, key):
+    if operator.isNumberType(key) or key.step is None:
+        return self.__original_getitem(key)
+    
+    res = self.__class__()
+    nb = len(self)
+    start = key.start or 0
+    stop  = key.stop or nb
+    if start >= nb:
+        return res
+    if stop > nb:
+        stop = nb
+    
+    for i in xrange(start, stop, key.step or 1):
+        res.append(self[i])
+    
+    return res
+
+def __fillVectorClass(klass):
+    klass.__add__ = __StdVector__add
+    klass.__mul__ = __StdVector__mul
+    klass.__imul__ = __StdVector__imul
+    klass.__original_getitem = klass.__getitem__
+    klass.__getitem__ = __StdVector__getitem
+    
+def __init_base_types():
+    
+    v_klasses = (StdStringVector,StdLongVector,StdDoubleVector,CommandInfoList, \
+                 AttributeInfoList,AttributeInfoListEx,DbData,DbDevInfos, \
+                 DbDevExportInfos,DbDevImportInfos,DbHistoryList, \
+                 DeviceDataHistoryList, StdGroupReplyVector, \
+                 StdGroupCmdReplyVector, StdGroupAttrReplyVector)
+
+    for v_klass in v_klasses:
+        __fillVectorClass(v_klass)
+
+def __doc_base_types():
+    
+    def document_enum(enum_name, desc):
+        import PyTango
+        __document_enum(PyTango, enum_name, desc)
+
+    document_enum("ExtractAs", """
+    Defines what will go into value field of DeviceAttribute, or what will
+    Attribute.get_write_value() return... Not all the possible values are valid
+    in all the cases.
+
+    Valid possible values are:
+        - Numpy    : Value will be stored in [value, w_value]. If the
+          attribute is an scalar, they will contain a value. If it's
+          an SPECTRUM or IMAGE it will be exported as a numpy array.
+        - Tuple    : Value will be stored in [value, w_value]. If the
+          attribute is an scalar, they will contain a value. If it's
+          an SPECTRUM or IMAGE it will be exported as a tuple or
+          tuple of tuples.
+        - List     : Value will be stored in [value, w_value]. If the
+          attribute is an scalar, they will contain a value. If it's
+          an SPECTRUM or IMAGE it will be exported as a list or list
+          of lists
+        - String   : The data will be stored 'as is', the binary data
+          as it comes from TangoC++ in 'value'.
+        - PyTango3 : Backward compatibility mode. If the attribute is
+          an scalar, value and w_scalar_value will contain a value.
+          If it's an SPECTRUM or IMAGE it will be exported as a flat
+          list in value, were both the read and the write part are
+          in value.
+        - Nothing  : The value will not be extracted from DeviceAttribute
+    """ )
+    
+    document_enum("CmdArgType", """
+    An enumeration representing the command argument type.
+
+        - DevVoid
+        - DevBoolean
+        - DevShort
+        - DevLong
+        - DevFloat
+        - DevDouble
+        - DevUShort
+        - DevULong
+        - DevString
+        - DevVarCharArray
+        - DevVarShortArray
+        - DevVarLongArray
+        - DevVarFloatArray
+        - DevVarDoubleArray
+        - DevVarUShortArray
+        - DevVarULongArray
+        - DevVarStringArray
+        - DevVarLongStringArray
+        - DevVarDoubleStringArray
+        - DevState
+        - ConstDevString
+        - DevVarBooleanArray
+        - DevUChar
+        - DevLong64
+        - DevULong64
+        - DevVarLong64Array
+        - DevVarULong64Array
+        - DevInt
+        - DevEncoded
+    """ )
+
+    document_enum("LockerLanguage", """
+    An enumeration representing the programming language in which the
+    client application who locked is written. 
+    
+        - CPP : C++/Python language
+        - JAVA : Java language
+    
+    New in PyTango 7.0.0
+    """ )
+
+    document_enum("MessBoxType", """
+    An enumeration representing the MessBoxType
+    
+        - STOP
+        - INFO
+    
+    New in PyTango 7.0.0
+    """ )
+
+    document_enum("PollObjType", """
+    An enumeration representing the PollObjType
+        
+        - POLL_CMD
+        - POLL_ATTR
+        - EVENT_HEARTBEAT
+        - STORE_SUBDEV
+    
+    New in PyTango 7.0.0
+    """ )
+
+    document_enum("PollCmdCode", """
+    An enumeration representing the PollCmdCode
+    
+        - POLL_ADD_OBJ
+        - POLL_REM_OBJ
+        - POLL_START
+        - POLL_STOP
+        - POLL_UPD_PERIOD
+        - POLL_REM_DEV
+        - POLL_EXIT
+        - POLL_REM_EXT_TRIG_OBJ
+        - POLL_ADD_HEARTBEAT
+        - POLL_REM_HEARTBEAT
+        
+    New in PyTango 7.0.0
+    """ )
+
+    document_enum("SerialModel", """
+    An enumeration representing the type of serialization performed by the device server
+    
+        - BY_DEVICE
+        - BY_CLASS
+        - BY_PROCESS
+        - NO_SYNC
+    """ )
+
+    document_enum("AttReqType", """
+    An enumeration representing the type of attribute request
+    
+        - READ_REQ
+        - WRITE_REQ
+    """ )
+
+    document_enum("LockCmdCode", """
+    An enumeration representing the LockCmdCode
+    
+        - LOCK_ADD_DEV
+        - LOCK_REM_DEV
+        - LOCK_UNLOCK_ALL_EXIT
+        - LOCK_EXIT
+        
+    New in PyTango 7.0.0
+    """ )
+
+    document_enum("LogLevel", """
+    An enumeration representing the LogLevel
+    
+        - LOG_OFF
+        - LOG_FATAL
+        - LOG_ERROR
+        - LOG_WARN
+        - LOG_INFO
+        - LOG_DEBUG
+        
+    New in PyTango 7.0.0
+    """ )
+
+    document_enum("LogTarget", """
+    An enumeration representing the LogTarget
+    
+        - LOG_CONSOLE
+        - LOG_FILE
+        - LOG_DEVICE
+        
+    New in PyTango 7.0.0
+    """ )
+
+    document_enum("EventType", """
+    An enumeration representing event type
+ 
+        - CHANGE_EVENT
+        - QUALITY_EVENT
+        - PERIODIC_EVENT
+        - ARCHIVE_EVENT
+        - USER_EVENT
+        - ATTR_CONF_EVENT
+        - DATA_READY_EVENT
+
+        *DATA_READY_EVENT - New in PyTango 7.0.0*
+    
+    """ )
+
+    document_enum("AttrSerialModel", """
+    An enumeration representing the AttrSerialModel
+    
+        - ATTR_NO_SYNC
+        - ATTR_BY_KERNEL
+        - ATTR_BY_USER
+        
+    New in PyTango 7.1.0
+    """ )
+    
+    document_enum("KeepAliveCmdCode", """
+    An enumeration representing the KeepAliveCmdCode
+
+        - EXIT_TH
+        
+    New in PyTango 7.0.0
+    """ )
+
+    document_enum("AccessControlType", """
+    An enumeration representing the AccessControlType
+    
+        - ACCESS_READ
+        - ACCESS_WRITE
+        
+    New in PyTango 7.0.0
+    """ )
+
+    document_enum("asyn_req_type", """
+    An enumeration representing the asynchronous request type
+    
+        - POLLING
+        - CALLBACK
+        - ALL_ASYNCH
+    """ )
+    
+    document_enum("cb_sub_model", """
+    An enumeration representing callback sub model
+    
+        - PUSH_CALLBACK
+        - PULL_CALLBACK
+    """ )
+    
+    document_enum("AttrQuality", """
+    An enumeration representing the attribute quality
+    
+        - ATTR_VALID
+        - ATTR_INVALID
+        - ATTR_ALARM
+        - ATTR_CHANGING
+        - ATTR_WARNING
+    """ )
+    
+    document_enum("AttrWriteType", """
+    An enumeration representing the attribute type
+    
+        - READ
+        - READ_WITH_WRITE
+        - WRITE
+        - READ_WRITE
+    """ )
+    
+    document_enum("AttrDataFormat", """
+    An enumeration representing the attribute format
+    
+        - SCALAR
+        - SPECTRUM
+        - IMAGE
+        - FMT_UNKNOWN
+    """ )
+    
+    document_enum("DevSource", """
+    An enumeration representing the device source for data
+    
+        - DEV
+        - CACHE
+        - CACHE_DEV
+    """ )
+    
+    document_enum("ErrSeverity", """
+    An enumeration representing the error severity
+    
+        - WARN
+        - ERR
+        - PANIC
+    """ )
+    
+    document_enum("DevState", """
+    An enumeration representing the device state
+    
+        - ON
+        - OFF
+        - CLOSE
+        - OPEN
+        - INSERT
+        - EXTRACT
+        - MOVING
+        - STANDBY
+        - FAULT
+        - INIT
+        - RUNNING
+        - ALARM
+        - DISABLE
+        - UNKNOWN
+    """ )
+    
+    document_enum("DispLevel", """
+    An enumeration representing the display level
+    
+        - OPERATOR
+        - EXPERT
+    """ )
+    
+    ArchiveEventInfo.__doc__ = """
+    A structure containing available archiving event information for an attribute
+    with the folowing members:
+        - archive_rel_change : (str) relative change that will generate an event
+        - archive_abs_change : (str) absolute change that will generate an event
+        - extensions : (sequence<str>) extensions (currently not used)"""
+
+    EventData.__doc__ = """
+    This class is used to pass data to the callback method when an event
+    is sent to the client. It contains the following public fields
+         - device : (DeviceProxy) The DeviceProxy object on which the call was
+           executed.
+         - attr_name : (str) The attribute name
+         - event : (str) The event name
+         - attr_value : (DeviceAttribute) The attribute data (DeviceAttribute)
+         - err : (bool) A boolean flag set to true if the request failed. False
+           otherwise
+         - errors : (sequence<DevError>) The error stack
+         - reception_date: (TimeVal)
+    """
+
+    document_method(EventData, "get_date", """
+    get_date(self) -> TimeVal
+
+            Returns the timestamp of the event.
+
+        Parameters : None
+        Return     : (TimeVal) the timestamp of the event
+
+        New in PyTango 7.0.0
+    """ )
+
+    AttrConfEventData.__doc__ = """
+    This class is used to pass data to the callback method when a
+    configuration event is sent to the client. It contains the
+    following public fields:
+        - device : (DeviceProxy) The DeviceProxy object on which the call was executed
+        - attr_name : (str) The attribute name
+        - event : (str) The event name
+        - attr_conf : (AttributeInfoEx) The attribute data
+        - err : (bool) A boolean flag set to true if the request failed. False
+          otherwise
+        - errors : (sequence<DevError>) The error stack
+        - reception_date: (TimeVal)
+    """
+
+    document_method(AttrConfEventData, "get_date", """
+    get_date(self) -> TimeVal
+
+            Returns the timestamp of the event.
+
+        Parameters : None
+        Return     : (TimeVal) the timestamp of the event
+
+        New in PyTango 7.0.0
+    """ )
+
+    AttributeAlarmInfo.__doc__ = """
+    A structure containing available alarm information for an attribute
+    with the folowing members:
+        - min_alarm : (str) low alarm level
+        - max_alarm : (str) high alarm level
+        - min_warning : (str) low warning level
+        - max_warning : (str) high warning level
+        - delta_t : (str) time delta
+        - delta_val : (str) value delta
+        - extensions : (StdStringVector) extensions (currently not used)"""
+
+    AttributeDimension.__doc__ = """
+    A structure containing x and y attribute data dimensions with
+    the following members:
+        - dim_x : (int) x dimension
+        - dim_y : (int) y dimension"""
+
+    AttributeEventInfo.__doc__ = """
+    A structure containing available event information for an attribute
+    with the folowing members:
+        - ch_event : (ChangeEventInfo) change event information
+        - per_event : (PeriodicEventInfo) periodic event information
+        - arch_event :  (ArchiveEventInfo) archiving event information"""
+
+    DeviceAttributeConfig.__doc__ = """
+    A base structure containing available information for an attribute
+    with the following members:
+        - name : (str) attribute name
+        - writable : (AttrWriteType) write type (R, W, RW, R with W)
+        - data_format : (AttrDataFormat) data format (SCALAR, SPECTRUM, IMAGE)
+        - data_type : (int) attribute type (float, string,..)
+        - max_dim_x : (int) first dimension of attribute (spectrum or image attributes)
+        - max_dim_y : (int) second dimension of attribute(image attribute)
+        - description : (int) attribute description
+        - label : (str) attribute label (Voltage, time, ...)
+        - unit : (str) attribute unit (V, ms, ...)
+        - standard_unit : (str) standard unit
+        - display_unit : (str) display unit
+        - format : (str) how to display the attribute value (ex: for floats could be '%6.2f')
+        - min_value : (str) minimum allowed value
+        - max_value : (str) maximum allowed value
+        - min_alarm : (str) low alarm level
+        - max_alarm : (str) high alarm level
+        - writable_attr_name : (str) name of the writable attribute
+        - extensions : (StdStringVector) extensions (currently not used)"""
+
+    AttributeInfo.__doc__ = """
+    A structure (inheriting from :class:`DeviceAttributeConfig`) containing
+    available information for an attribute with the following members:
+        - disp_level : (DispLevel) display level (OPERATOR, EXPERT)
+
+        Inherited members are:
+            - name : (str) attribute name
+            - writable : (AttrWriteType) write type (R, W, RW, R with W)
+            - data_format : (AttrDataFormat) data format (SCALAR, SPECTRUM, IMAGE)
+            - data_type : (int) attribute type (float, string,..)
+            - max_dim_x : (int) first dimension of attribute (spectrum or image attributes)
+            - max_dim_y : (int) second dimension of attribute(image attribute)
+            - description : (int) attribute description
+            - label : (str) attribute label (Voltage, time, ...)
+            - unit : (str) attribute unit (V, ms, ...)
+            - standard_unit : (str) standard unit
+            - display_unit : (str) display unit
+            - format : (str) how to display the attribute value (ex: for floats could be '%6.2f')
+            - min_value : (str) minimum allowed value
+            - max_value : (str) maximum allowed value
+            - min_alarm : (str) low alarm level
+            - max_alarm : (str) high alarm level
+            - writable_attr_name : (str) name of the writable attribute
+            - extensions : (StdStringVector) extensions (currently not used)"""
+
+    AttributeInfoEx.__doc__ = """
+    A structure (inheriting from :class:`AttributeInfo`) containing
+    available information for an attribute with the following members:
+        - alarms : object containing alarm information (see AttributeAlarmInfo).
+        - events : object containing event information (see AttributeEventInfo).
+        - sys_extensions : StdStringVector
+
+        Inherited members are:
+            - name : (str) attribute name
+            - writable : (AttrWriteType) write type (R, W, RW, R with W)
+            - data_format : (AttrDataFormat) data format (SCALAR, SPECTRUM, IMAGE)
+            - data_type : (int) attribute type (float, string,..)
+            - max_dim_x : (int) first dimension of attribute (spectrum or image attributes)
+            - max_dim_y : (int) second dimension of attribute(image attribute)
+            - description : (int) attribute description
+            - label : (str) attribute label (Voltage, time, ...)
+            - unit : (str) attribute unit (V, ms, ...)
+            - standard_unit : (str) standard unit
+            - display_unit : (str) display unit
+            - format : (str) how to display the attribute value (ex: for floats could be '%6.2f')
+            - min_value : (str) minimum allowed value
+            - max_value : (str) maximum allowed value
+            - min_alarm : (str) low alarm level
+            - max_alarm : (str) high alarm level
+            - writable_attr_name : (str) name of the writable attribute
+            - extensions : (StdStringVector) extensions (currently not used)
+            - disp_level : (DispLevel) display level (OPERATOR, EXPERT)"""
+
+    ChangeEventInfo.__doc__ = """
+    A structure containing available change event information for an attribute
+    with the folowing members:
+        - rel_change : (str) relative change that will generate an event
+        - abs_change : (str) absolute change that will generate an event
+        - extensions : (StdStringVector) extensions (currently not used)"""
+
+    DevCommandInfo.__doc__ = """
+    A device command info with the following members:
+        - cmd_name : (str) command name
+        - cmd_tag : command as binary value (for TACO)
+        - in_type : (CmdArgType) input type
+        - out_type : (CmdArgType) output type
+        - in_type_desc : (str) description of input type
+        - out_type_desc : (str) description of output type
+
+    New in PyTango 7.0.0"""
+
+    CommandInfo.__doc__ = """
+    A device command info (inheriting from :class:`DevCommandInfo`) with the following members:
+        - disp_level : (DispLevel) command display level
+
+        Inherited members are (from :class:`DevCommandInfo`):
+            - cmd_name : (str) command name
+            - cmd_tag : (str) command as binary value (for TACO)
+            - in_type : (CmdArgType) input type
+            - out_type : (CmdArgType) output type
+            - in_type_desc : (str) description of input type
+            - out_type_desc : (str) description of output type"""
+
+    DataReadyEventData.__doc__ = """
+    This class is used to pass data to the callback method when an
+    attribute data ready event is sent to the clien. It contains the
+    following public fields:
+        - device : (DeviceProxy) The DeviceProxy object on which the call was executed
+        - attr_name : (str) The attribute name
+        - event : (str) The event name
+        - attr_data_type : (int) The attribute data type
+        - ctr : (int) The user counter. Set to 0 if not defined when sent by the
+          server
+        - err : (bool) A boolean flag set to true if the request failed. False
+          otherwise
+        - errors : (sequence<DevError>) The error stack
+        - reception_date: (TimeVal)
+
+        New in PyTango 7.0.0"""
+
+    document_method(DataReadyEventData, "get_date", """
+    get_date(self) -> TimeVal
+
+            Returns the timestamp of the event.
+
+        Parameters : None
+        Return     : (TimeVal) the timestamp of the event
+
+        New in PyTango 7.0.0
+    """ )
+
+
+    Except.__doc__ = """
+    A containner for the static methods:
+        - throw_exception
+        - re_throw_exception
+        - print_exception
+        - compare_exception"""
+
+    DevError.__doc__ = """
+    Structure describing any error resulting from a command execution,
+    or an attribute query, with following members:
+        - reason : (str)
+        - severity : (ErrSeverity) error severty (WARN, ERR, PANIC)
+        - desc : (str) error description
+        - origin : (str) Tango server method in which the error happened"""
+
+    TimeVal.__doc__ = """
+    Time value structure with the following members
+        - tv_sec : seconds
+        - tv_usec : microseconds
+        - tv_nsec : nanoseconds"""
+
+def init(doc=True):
+    __init_base_types()
+    if doc:
+        __doc_base_types()
\ No newline at end of file
diff --git a/PyTango/callback.py b/PyTango/callback.py
new file mode 100644
index 0000000..1ee40bb
--- /dev/null
+++ b/PyTango/callback.py
@@ -0,0 +1,82 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = []
+
+__docformat__ = "restructuredtext"
+
+from _PyTango import CmdDoneEvent, AttrReadEvent, AttrWrittenEvent
+# __CallBackAutoDie, __CallBackPushEvent
+from utils import document_method as __document_method
+
+
+def __init_Callback():
+    pass
+
+def __doc_Callback():
+    CmdDoneEvent.__doc__ = """
+        This class is used to pass data to the callback method in
+        asynchronous callback model for command execution.
+
+        It has the following members:
+            - device     : (DeviceProxy) The DeviceProxy object on which the call was executed.
+            - cmd_name   : (str) The command name
+            - argout_raw : (DeviceData) The command argout
+            - argout     : The command argout
+            - err        : (bool) A boolean flag set to true if the command failed. False otherwise
+            - errors     : (sequence<DevError>) The error stack
+            - ext        :
+    """
+
+    AttrReadEvent.__doc__ = """
+        This class is used to pass data to the callback method in
+        asynchronous callback model for read_attribute(s) execution.
+
+        It has the following members:
+            - device     : (DeviceProxy) The DeviceProxy object on which the call was executed
+            - attr_names : (sequence<str>) The attribute name list
+            - argout     : (DeviceAttribute) The attribute value
+            - err        : (bool) A boolean flag set to true if the command failed. False otherwise
+            - errors     : (sequence<DevError>) The error stack
+            - ext        :
+    """
+
+    AttrWrittenEvent.__doc__ = """
+        This class is used to pass data to the callback method in
+        asynchronous callback model for write_attribute(s) execution
+
+        It has the following members:
+            - device     : (DeviceProxy) The DeviceProxy object on which the call was executed
+            - attr_names : (sequence<str>) The attribute name list
+            - err        : (bool) A boolean flag set to true if the command failed. False otherwise
+            - errors     : (NamedDevFailedList) The error stack
+            - ext        :
+    """
+
+def init(doc=True):
+    __init_Callback()
+    if doc:
+        __doc_Callback()
diff --git a/PyTango/connection.py b/PyTango/connection.py
new file mode 100644
index 0000000..3302ad8
--- /dev/null
+++ b/PyTango/connection.py
@@ -0,0 +1,546 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = []
+
+__docformat__ = "restructuredtext"
+
+from _PyTango import Connection, DeviceData, __CallBackAutoDie, CmdArgType
+from _PyTango import DeviceProxy, Database
+from _PyTango import ExtractAs
+from utils import document_method as __document_method
+import operator
+
+def __CallBackAutoDie__cmd_ended_aux(fn):
+    def __new_fn(cmd_done_event):
+        try:
+            cmd_done_event.argout = cmd_done_event.argout_raw.extract(
+                                       self.defaultCommandExtractAs)
+        except Exception:
+            pass
+        return fn(cmd_done_event)
+    return __new_fn
+
+def __get_command_inout_param(self, cmd_name, cmd_param=None):
+    if cmd_param is None:
+        return DeviceData()
+    
+    if isinstance(cmd_param, DeviceData):
+        return cmd_param
+
+    if isinstance(self, DeviceProxy):
+        # This is not part of 'Connection' interface, but
+        # DeviceProxy only.
+        info = self.command_query(cmd_name)
+        param = DeviceData()
+        param.insert(info.in_type, cmd_param)
+        return param
+    elif isinstance(self, Database):
+        # I just try to guess types DevString and DevVarStringArray
+        # as they are used for Database
+        param = DeviceData()
+        if isinstance(cmd_param, str):
+            param.insert(CmdArgType.DevString, cmd_param)
+            return param
+        elif operator.isSequenceType(cmd_param) and all([isinstance(x,str) for x in cmd_param]):
+            param.insert(CmdArgType.DevVarStringArray, cmd_param)
+            return param
+        else:
+            raise TypeError("command_inout() parameter must be a DeviceData object or a string or a sequence of strings")
+    else:
+        raise TypeError("command_inout() parameter must be a DeviceData object.")
+
+def __Connection__command_inout(self, name, *args, **kwds):
+    """
+    command_inout( self, cmd_name, cmd_param=None) -> any
+
+            Execute a command on a device.
+            
+        Parameters :
+                - cmd_name  : (str) Command name.
+                - cmd_param : (any) It should be a value of the type expected by the
+                              command or a DeviceData object with this value inserted.
+                              It can be ommited if the command should not get any argument.
+        Return     : The result of the command. The type depends on the command. It may be None.
+
+        Throws     : ConnectionFailed, CommunicationFailed, DeviceUnlocked, DevFailed from device 
+    """
+    r = Connection.command_inout_raw(self, name, *args, **kwds)
+    if isinstance(r, DeviceData):
+        try:
+            return r.extract(self.defaultCommandExtractAs)
+        except Exception:
+            return None
+    else:
+        return r
+
+def __Connection__command_inout_raw(self, cmd_name, cmd_param = None):
+    """
+    command_inout_raw( self, cmd_name, cmd_param=None) -> DeviceData
+
+            Execute a command on a device.
+        
+        Parameters :
+                - cmd_name  : (str) Command name.
+                - cmd_param : (any) It should be a value of the type expected by the
+                              command or a DeviceData object with this value inserted.
+                              It can be ommited if the command should not get any argument.
+        Return     : A DeviceData object.
+
+        Throws     : ConnectionFailed, CommunicationFailed, DeviceUnlocked, DevFailed from device 
+    """
+    param = __get_command_inout_param(self, cmd_name, cmd_param)
+    return self.__command_inout(cmd_name, param)
+
+
+
+def __Connection__command_inout_asynch(self, cmd_name, *args):
+    """
+    command_inout_asynch(self, cmd_name, cmd_param=None, forget=False) -> id
+    
+            Execute asynchronously (polling model) a command on a device
+            
+        Parameters :
+                - cmd_name  : (str) Command name.
+                - cmd_param : (any) It should be a value of the type expected by the
+                              command or a DeviceData object with this value inserted.
+                              It can be ommited if the command should not get any argument.
+                              If the command sould get no argument and you want
+                              to set the 'forget' param, use None for cmd_param.
+                - forget    : (bool) If this flag is set to true, this means that the client
+                              does not care at all about the server answer and will even
+                              not try to get it. A false default value is provided. Please,
+                              note that device re-connection will not take place (in case
+                              it is needed) if the fire and forget mode is used. Therefore,
+                              an application using only fire and forget requests is not able
+                              to automatically re-connnect to device.
+        Return     : (int) This call returns an asynchronous call identifier which is
+                     needed to get the command result (see command_inout_reply)
+
+        Throws     : ConnectionFailed, TypeError, anything thrown by command_query
+        
+    command_inout_asynch( self, cmd_name, callback) -> None
+    command_inout_asynch( self, cmd_name, cmd_param, callback) -> None
+    
+            Execute asynchronously (callback model) a command on a device.
+            
+        Parameters :
+                - cmd_name  : (str) Command name.
+                - cmd_param : (any)It should be a value of the type expected by the
+                              command or a DeviceData object with this value inserted.
+                              It can be ommited if the command should not get any argument.
+                - callback  : Any callable object (function, lambda...) or any oject
+                              with a method named "cmd_ended".
+        Return     : None
+
+        Throws     : ConnectionFailed, TypeError, anything thrown by command_query
+    """
+    if len(args) == 0: # command_inout_asynch()
+        argin = DeviceData()
+        forget = False
+        return self.__command_inout_asynch_id(cmd_name, argin, forget)
+    elif len(args) == 1:
+        if callable(args[0]): # command_inout_asynch(lambda)
+            cb = __CallBackAutoDie()
+            cb.cmd_ended = __CallBackAutoDie__cmd_ended_aux(args[0])
+            argin = __get_command_inout_param(self, cmd_name)
+            return self.__command_inout_asynch_cb(cmd_name, argin, cb)
+        elif hasattr(args[0], 'cmd_ended'): # command_inout_asynch(Cbclass)
+            cb = __CallBackAutoDie()
+            cb.cmd_ended = __CallBackAutoDie__cmd_ended_aux(args[0].cmd_ended)
+            argin = __get_command_inout_param(self, cmd_name)
+            return self.__command_inout_asynch_cb(cmd_name, argin, cb)
+        else: # command_inout_asynch(value)
+            argin = __get_command_inout_param(self, cmd_name, args[0])
+            forget = False
+            return self.__command_inout_asynch_id(cmd_name, argin, forget)
+    elif len(args) == 2:
+        if callable(args[1]): #command_inout_asynch( value, lambda)
+            cb = __CallBackAutoDie()
+            cb.cmd_ended = __CallBackAutoDie__cmd_ended_aux(args[1])
+            argin = __get_command_inout_param(self, cmd_name, args[0])
+            return self.__command_inout_asynch_cb(cmd_name, argin, cb)
+        elif hasattr(args[1], 'cmd_ended'): #command_inout_asynch(value, cbClass)
+            cb = __CallBackAutoDie()
+            cb.cmd_ended = __CallBackAutoDie__cmd_ended_aux(args[1].cmd_ended)
+            argin = __get_command_inout_param(self, cmd_name, args[0])
+            return self.__command_inout_asynch_cb(cmd_name, argin, cb)
+        else: # command_inout_asynch(value, forget)
+            argin = __get_command_inout_param(self, cmd_name, args[0])
+            forget = bool(args[1])
+            return self.__command_inout_asynch_id(cmd_name, argin, forget)
+    else:
+        raise TypeError("Wrong number of attributes!")
+
+def __Connection__command_inout_reply(self, idx, timeout=None):
+    """
+    command_inout_reply(self, id) -> DeviceData
+    
+            Check if the answer of an asynchronous command_inout is arrived
+            (polling model). If the reply is arrived and if it is a valid
+            reply, it is returned to the caller in a DeviceData object. If
+            the reply is an exception, it is re-thrown by this call. An
+            exception is also thrown in case of the reply is not yet arrived.
+
+        Parameters :
+            - id      : (int) Asynchronous call identifier.
+        Return     : (DeviceData)
+        Throws     : AsynCall, AsynReplyNotArrived, CommunicationFailed, DevFailed from device
+
+    command_inout_reply(self, id, timeout) -> DeviceData
+    
+            Check if the answer of an asynchronous command_inout is arrived
+            (polling model). id is the asynchronous call identifier. If the
+            reply is arrived and if it is a valid reply, it is returned to
+            the caller in a DeviceData object. If the reply is an exception,
+            it is re-thrown by this call. If the reply is not yet arrived,
+            the call will wait (blocking the process) for the time specified
+            in timeout. If after timeout milliseconds, the reply is still
+            not there, an exception is thrown. If timeout is set to 0, the
+            call waits until the reply arrived.
+
+        Parameters :
+            - id      : (int) Asynchronous call identifier.
+            - timeout : (int)
+        Return     : (DeviceData)
+        Throws     : AsynCall, AsynReplyNotArrived, CommunicationFailed, DevFailed from device
+    """
+    if timeout is None:
+        r = self.command_inout_reply_raw(idx)
+    else:
+        r = self.command_inout_reply_raw(idx, timeout)
+    
+    if isinstance(r, DeviceData):
+        try:
+            return r.extract(self.defaultCommandExtractAs)
+        except Exception:
+            return None
+    else:
+        return r
+    
+def __init_Connection():
+    Connection.defaultCommandExtractAs = ExtractAs.Numpy
+    Connection.command_inout_raw = __Connection__command_inout_raw
+    Connection.command_inout = __Connection__command_inout
+    Connection.command_inout_asynch = __Connection__command_inout_asynch
+    Connection.command_inout_reply = __Connection__command_inout_reply
+    
+def __doc_Connection():
+    def document_method(method_name, desc, append=True):
+        return __document_method(Connection, method_name, desc, append)
+
+    Connection.__doc__ = """
+        The abstract Connection class for DeviceProxy. Not to be initialized directly.
+    """
+
+    document_method("dev_name", """
+    dev_name(self) -> str
+    
+            Return the device name as it is stored locally
+
+        Parameters : None
+        Return     : (str)
+    """)
+
+    document_method("get_db_host", """
+    get_db_host(self) -> str
+    
+            Returns a string with the database host.
+
+        Parameters : None
+        Return     : (str)
+
+        New in PyTango 7.0.0
+    """)
+
+    document_method("get_db_port", """
+    get_db_port(self) -> str
+    
+            Returns a string with the database port.
+
+        Parameters : None
+        Return     : (str)
+
+        New in PyTango 7.0.0
+    """)
+
+    document_method("get_db_port_num", """
+    get_db_port_num(self) -> int
+    
+            Returns an integer with the database port.
+
+        Parameters : None
+        Return     : (int)
+
+        New in PyTango 7.0.0
+    """)
+
+    document_method("get_from_env_var", """
+    get_from_env_var(self) -> bool
+    
+            Returns True if determined by environment variable or
+            False otherwise
+
+        Parameters : None
+        Return     : (bool)
+
+        New in PyTango 7.0.0
+    """)
+
+
+    document_method("connect", """
+    connect(self, corba_name) -> None
+    
+            Creates a connection to a TANGO device using it's stringified
+            CORBA reference i.e. IOR or corbaloc.
+
+        Parameters :
+            - corba_name : (str) Name of the CORBA object
+        Return     : None
+
+        New in PyTango 7.0.0
+    """)
+
+    document_method("reconnect", """
+    reconnect(self, db_used) -> None
+    
+            Reconnecto to a CORBA object.
+
+        Parameters :
+            - db_used : (bool) Use thatabase
+        Return     : None
+
+        New in PyTango 7.0.0
+    """)
+
+    document_method("get_idl_version", """
+    get_idl_version(self) -> int
+    
+            Get the version of the Tango Device interface implemented
+            by the device
+
+        Parameters : None
+        Return     : (int)
+    """)
+
+    document_method("set_timeout_millis", """
+    set_timeout_millis(self, timeout) -> None
+    
+            Set client side timeout for device in milliseconds. Any method
+            which takes longer than this time to execute will throw an
+            exception
+
+        Parameters :
+            - timeout : integer value of timeout in milliseconds
+        Return     : None
+        Example    :
+                    dev.set_timeout_millis(1000)
+    """)
+
+    document_method("get_timeout_millis", """
+    get_timeout_millis(self) -> int
+    
+            Get the client side timeout in milliseconds
+
+        Parameters : None
+        Return     : (int)
+    """)
+
+    document_method("get_source", """
+    get_source(self) -> DevSource
+    
+            Get the data source(device, polling buffer, polling buffer
+            then device) used by command_inout or read_attribute methods
+
+        Parameters : None
+        Return     : (DevSource)
+        Example    :
+                    source = dev.get_source()
+                    if source == DevSource.CACHE_DEV : ...
+    """)
+
+    document_method("set_source", """
+    set_source(self, source) -> None
+    
+            Set the data source(device, polling buffer, polling buffer
+            then device) for command_inout and read_attribute methods.
+
+        Parameters :
+            - source: (DevSource) constant.
+        Return     : None
+        Example    :
+                    dev.set_source(DevSource.CACHE_DEV)
+    """)
+
+    document_method("get_transparency_reconnection", """
+    get_transparency_reconnection(self) -> bool
+    
+            Returns the device transparency reconnection flag.
+
+        Parameters : None
+        Return     : (bool) True if transparency reconnection is set
+                            or False otherwise
+    """)
+
+    document_method("set_transparency_reconnection", """
+    set_transparency_reconnection(self, yesno) -> None
+    
+            Set the device transparency reconnection flag
+
+        Parameters :
+            "    - val : (bool) True to set transparency reconnection
+            "                   or False otherwise
+        Return     : None
+    """)
+
+    document_method("command_inout_reply_raw", """
+    command_inout_reply_raw(self, id) -> DeviceData
+    
+            Check if the answer of an asynchronous command_inout is arrived
+            (polling model). If the reply is arrived and if it is a valid
+            reply, it is returned to the caller in a DeviceData object. If
+            the reply is an exception, it is re-thrown by this call. An
+            exception is also thrown in case of the reply is not yet arrived.
+
+        Parameters :
+            - id      : (int) Asynchronous call identifier.
+        Return     : (DeviceData)
+        Throws     : AsynCall, AsynReplyNotArrived, CommunicationFailed, DevFailed from device
+    """)
+
+    document_method("command_inout_reply_raw", """
+    command_inout_reply_raw(self, id, timeout) -> DeviceData
+    
+            Check if the answer of an asynchronous command_inout is arrived
+            (polling model). id is the asynchronous call identifier. If the
+            reply is arrived and if it is a valid reply, it is returned to
+            the caller in a DeviceData object. If the reply is an exception,
+            it is re-thrown by this call. If the reply is not yet arrived,
+            the call will wait (blocking the process) for the time specified
+            in timeout. If after timeout milliseconds, the reply is still
+            not there, an exception is thrown. If timeout is set to 0, the
+            call waits until the reply arrived.
+
+        Parameters :
+            - id      : (int) Asynchronous call identifier.
+            - timeout : (int)
+        Return     : (DeviceData)
+        Throws     : AsynCall, AsynReplyNotArrived, CommunicationFailed, DevFailed from device
+    """)
+
+    #//
+    #// Asynchronous methods
+    #//
+
+    document_method("get_asynch_replies", """
+    get_asynch_replies(self) -> None
+    
+            Try to obtain data returned by a command asynchronously
+            requested. This method does not block if the reply has not yet
+            arrived. It fires callback for already arrived replies.
+            
+        Parameters : None
+        Return     : None
+
+        New in PyTango 7.0.0
+    """)
+
+    document_method("get_asynch_replies", """
+    get_asynch_replies(self, call_timeout) -> None
+    
+            Try to obtain data returned by a command asynchronously
+            requested. This method blocks for the specified timeout if the
+            reply is not yet arrived. This method fires callback when the
+            reply arrived. If the timeout is set to 0, the call waits
+            undefinitely for the reply
+            
+        Parameters :
+            - call_timeout : (int) timeout in miliseconds
+        Return     : None
+
+        New in PyTango 7.0.0
+    """)
+
+    document_method("cancel_asynch_request", """
+    cancel_asynch_request(self, id ) -> None
+
+            Cancel a running asynchronous request
+            
+            This is a client side call. Obviously, the call cannot be
+            aborted while it is running in the device.
+            
+        Parameters :
+            - id : The asynchronous call identifier
+        Return     : None
+
+            New in PyTango 7.0.0
+    """)
+
+    document_method("cancel_all_polling_asynch_request", """
+    cancel_all_polling_asynch_request(self) -> None
+    
+            Cancel all running asynchronous request
+            
+            This is a client side call. Obviously, the calls cannot be
+            aborted while it is running in the device.
+            
+        Parameters : None
+        Return     : None
+
+        New in PyTango 7.0.0
+    """)
+
+    #//
+    #// Control access related methods
+    #//
+        
+    document_method("get_access_control", """
+    get_access_control(self) -> AccessControlType
+    
+            Returns the current access control type
+            
+        Parameters : None
+        Return     : (AccessControlType) The current access control type
+
+        New in PyTango 7.0.0
+    """)
+
+    document_method("set_access_control", """
+    set_access_control(self, acc) -> None
+            Sets the current access control type
+            
+        Parameters :
+            - acc: (AccessControlType) the type of access
+                   control to set
+        Return     : None
+
+        New in PyTango 7.0.0
+    """)
+
+def init(doc=True):
+    __init_Connection()
+    if doc:
+        __doc_Connection()
diff --git a/PyTango/db.py b/PyTango/db.py
new file mode 100644
index 0000000..b125e9e
--- /dev/null
+++ b/PyTango/db.py
@@ -0,0 +1,2053 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = []
+
+__docformat__ = "restructuredtext"
+
+import types
+import operator
+
+from _PyTango import StdStringVector
+from _PyTango import Database, DbDatum, DbData
+from _PyTango import DbDevInfo, DbDevInfos
+from _PyTango import DbDevImportInfo, DbDevExportInfo
+from _PyTango import DbDevImportInfos, DbDevExportInfos
+from _PyTango import DbHistory, DbServerInfo
+
+from utils import seq_2_StdStringVector
+from utils import seq_2_DbDevInfos
+from utils import seq_2_DbDevExportInfos
+from utils import seq_2_DbData
+from utils import DbData_2_dict
+from utils import document_method as __document_method
+
+#-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
+# DbDatum extension
+#-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
+
+def __DbDatum___setitem(self, k, v):
+    self.value_string[k] = v
+
+def __DbDatum___delitem(self, k):
+    self.value_string.__delitem__(k)
+
+def __DbDatum_append(self, v):
+    self.value_string.append(v)
+
+def __DbDatum_extend(self, v):
+    self.value_string.extend(v)
+
+def __DbDatum___imul(self, n):
+    self.value_string *= n
+
+def __init_DbDatum():
+    DbDatum.__len__      = lambda self : len(self.value_string)
+    DbDatum.__getitem__  = lambda self, k : self.value_string[k]
+    DbDatum.__setitem__  = __DbDatum___setitem
+    DbDatum.__delitem__  = __DbDatum___delitem
+    DbDatum.__iter__     = lambda self : self.value_string.__iter__()
+    DbDatum.__contains__ = lambda self, v : self.value_string.__contains__(v)
+    DbDatum.__add__      = lambda self, seq : self.value_string + seq
+    DbDatum.__mul__      = lambda self, n : self.value_string * n
+    DbDatum.__imul__     = __DbDatum___imul
+    DbDatum.append       = __DbDatum_append
+    DbDatum.extend       = __DbDatum_extend
+    
+#    DbDatum.__str__      = __DbDatum___str__
+#    DbDatum.__repr__      = __DbDatum___repr__
+
+#-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
+# Database extension
+#-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
+
+def __Database__add_server(self, servname, dev_info):
+    """
+        add_server( self, servname, dev_info) -> None
+
+                Add a (group of) devices to the database.
+
+            Parameters :
+                - servname : (str) server name
+                - dev_info : (sequence<DbDevInfo> | DbDevInfos | DbDevInfo) containing the server device(s) information
+            Return     : None
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """
+
+    if not operator.isSequenceType(dev_info) and \
+       not isinstance(dev_info, DbDevInfo):
+        raise TypeError('value must be a DbDevInfos, a seq<DbDevInfo> or ' \
+                        'a DbDevInfo')
+
+    if isinstance(dev_info, DbDevInfos):
+        pass
+    elif isinstance(dev_info, DbDevInfo):
+        dev_info = seq_2_DbDevInfos((dev_info,))
+    else:
+        dev_info = seq_2_DbDevInfos(dev_info)
+    self._add_server(servname, dev_info)
+
+def __Database__export_server(self, dev_info):
+    """
+        export_server(self, dev_info) -> None
+
+                Export a group of devices to the database.
+
+            Parameters :
+                - devinfo : (sequence<DbDevExportInfo> | DbDevExportInfos | DbDevExportInfo)
+                            containing the device(s) to export information
+            Return     : None
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """
+
+    if not operator.isSequenceType(dev_info) and \
+       not isinstance(dev_info, DbDevExportInfo):
+        raise TypeError('value must be a DbDevExportInfos, a seq<DbDevExportInfo> or ' \
+                        'a DbDevExportInfo')
+
+    if isinstance(dev_info, DbDevExportInfos):
+        pass
+    elif isinstance(dev_info, DbDevExportInfo):
+        dev_info = seq_2_DbDevExportInfos((dev_info),)
+    else:
+        dev_info = seq_2_DbDevExportInfos(dev_info)
+    self._export_server(dev_info)
+
+def __Database__generic_get_property(self, obj_name, value, f):
+    """internal usage"""
+    ret = None
+    if isinstance(value, DbData):
+        new_value = value
+    elif isinstance(value, DbDatum):
+        new_value = DbData()
+        new_value.append(value)
+    elif type(value) in types.StringTypes:
+        new_value = DbData()
+        new_value.append(DbDatum(value))
+    elif operator.isSequenceType(value):
+        new_value = DbData()
+        for e in value:
+            if isinstance(e, DbDatum):
+                new_value.append(e)
+            else:
+                new_value.append(DbDatum(str(e)))
+    elif operator.isMappingType(value):
+        new_value = DbData()
+        for k, v in value.iteritems():
+            if isinstance(v, DbDatum):
+                new_value.append(v)
+            else:
+                new_value.append(DbDatum(k))
+        ret = value
+    else:
+        raise TypeError('value must be a string, PyTango.DbDatum, '\
+                        'PyTango.DbData, a sequence or a dictionary')
+
+    f(obj_name, new_value)
+    if ret is None: ret = {}
+    return DbData_2_dict(new_value, ret)
+
+def __Database__generic_put_property(self, obj_name, value, f):
+    """internal usage"""
+    if isinstance(value, DbData):
+        pass
+    elif isinstance(value, DbDatum):
+        new_value = DbData()
+        new_value.append(value)
+        value = new_value
+    elif operator.isSequenceType(value) and not type(value) in types.StringTypes:
+        new_value = seq_2_DbData(value)
+    elif operator.isMappingType(value):
+        new_value = DbData()
+        for k, v in value.iteritems():
+            if isinstance(v, DbDatum):
+                new_value.append(v)
+                continue
+            db_datum = DbDatum(k)
+            if operator.isSequenceType(v) and not type(v) in types.StringTypes:
+                seq_2_StdStringVector(v, db_datum.value_string)
+            else:
+                db_datum.value_string.append(str(v))
+            new_value.append(db_datum)
+        value = new_value
+    else:
+        raise TypeError('value must be a PyTango.DbDatum, PyTango.DbData,'\
+                        'a sequence<DbDatum> or a dictionary')
+    return f(obj_name, value)
+
+def __Database__generic_delete_property(self, obj_name, value, f):
+    """internal usage"""
+    if isinstance(value, DbData):
+        new_value = value
+    elif isinstance(value, DbDatum):
+        new_value = DbData()
+        new_value.append(value)
+    elif type(value) in types.StringTypes:
+        new_value = DbData()
+        new_value.append(DbDatum(value))
+    elif operator.isSequenceType(value):
+        new_value = DbData()
+        for e in value:
+            if isinstance(e, DbDatum):
+                new_value.append(e)
+            else:
+                new_value.append(DbDatum(str(e)))
+    elif operator.isMappingType(value):
+        new_value = DbData()
+        for k, v in value.iteritems():
+            if isinstance(v, DbDatum):
+                new_value.append(v)
+            else:
+                new_value.append(DbDatum(k))
+    else:
+        raise TypeError('value must be a string, PyTango.DbDatum, '\
+                        'PyTango.DbData, a sequence or a dictionary')
+
+    return f(obj_name, new_value)
+
+def __Database__put_property(self, obj_name, value):
+    """
+        put_property(self, obj_name, value) -> None
+
+            Insert or update a list of properties for the specified object.
+        Parameters :
+            - obj_name : (str) object name
+            - value : can be one of the following:
+                1. DbDatum - single property data to be inserted
+                2. DbData - several property data to be inserted
+                3. sequence<DbDatum> - several property data to be inserted
+                4. dict<str, DbDatum> - keys are property names and value has data to be inserted
+                5. dict<str, obj> - keys are property names and str(obj) is property value
+                6. dict<str, seq<str>> - keys are property names and value has data to be inserted
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)"""
+
+    return __Database__generic_put_property(self, obj_name, value, self._put_property)
+
+def __Database__get_property(self, obj_name, value):
+    """
+        get_property(self, obj_name, value) -> dict<str, seq<str>>
+
+                Query the database for a list of object (i.e non-device) properties.
+
+            Parameters :
+                - obj_name : (str) object name
+                - value : can be one of the following:
+                    1. str [in] - single property data to be fetched
+                    2. DbDatum [in] - single property data to be fetched
+                    3. DbData [in,out] - several property data to be fetched
+                       In this case (direct C++ API) the DbData will be filled with the
+                       property values
+                    4. sequence<str> [in] - several property data to be fetched
+                    5. sequence<DbDatum> [in] - several property data to be fetched
+                    6. dict<str, obj> [in,out] - keys are property names
+                       In this case the given dict values will be changed to contain the
+                       several property values
+
+            Return     : a dictionary which keys are the property names the value
+                        associated with each key being a a sequence of strings being the
+                        property value.
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)"""
+    return __Database__generic_get_property(self, obj_name, value, self._get_property)
+
+def __Database__get_property_forced(self, obj_name, value):
+    return __Database__generic_get_property(self, obj_name, value, self._get_property_forced)
+
+__Database__get_property_forced.__doc__ = __Database__get_property.__doc__
+
+def __Database__delete_property(self, obj_name, value):
+    """
+        delete_property(self, obj_name, value) -> None
+
+                Delete a the given of properties for the specified object.
+
+            Parameters :
+                - obj_name : (str) object name
+                - value : can be one of the following:
+                    1. str [in] - single property data to be deleted
+                    2. DbDatum [in] - single property data to be deleted
+                    3. DbData [in] - several property data to be deleted
+                    4. sequence<string> [in]- several property data to be deleted
+                    5. sequence<DbDatum> [in] - several property data to be deleted
+                    6. dict<str, obj> [in] - keys are property names to be deleted
+                                             (values are ignored)
+                    7. dict<str, DbDatum> [in] - several DbDatum.name are property names
+                                                 to be deleted (keys are ignored)
+            Return     : None
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)"""
+    return __Database__generic_delete_property(self, obj_name, value, self._delete_property)
+
+def __Database__get_device_property(self, dev_name, value):
+    """
+        get_device_property(self, dev_name, value) -> dict<str, seq<str>>
+
+            Query the database for a list of device properties.
+
+            Parameters :
+                - dev_name : (str) object name
+                - value : can be one of the following:
+                    1. str [in] - single property data to be fetched
+                    2. DbDatum [in] - single property data to be fetched
+                    3. DbData [in,out] - several property data to be fetched
+                       In this case (direct C++ API) the DbData will be filled with the
+                       property values
+                    4. sequence<str> [in] - several property data to be fetched
+                    5. sequence<DbDatum> [in] - several property data to be fetched
+                    6. dict<str, obj> [in,out] - keys are property names
+                       In this case the given dict values will be changed to contain the
+                       several property values
+
+            Return     : a dictionary which keys are the property names the value
+                        associated with each key being a a sequence of strings being the
+                        property value.
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)"""
+    return __Database__generic_get_property(self, dev_name, value, self._get_device_property)
+
+def __Database__put_device_property(self, dev_name, value):
+    """
+        put_device_property(self, dev_name, value) -> None
+
+            Insert or update a list of properties for the specified device.
+
+            Parameters :
+                - dev_name : (str) object name
+                - value : can be one of the following:
+                    1. DbDatum - single property data to be inserted
+                    2. DbData - several property data to be inserted
+                    3. sequence<DbDatum> - several property data to be inserted
+                    4. dict<str, DbDatum> - keys are property names and value has data to be inserted
+                    5. dict<str, obj> - keys are property names and str(obj) is property value
+                    6. dict<str, seq<str>> - keys are property names and value has data to be inserted
+            Return     : None
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)"""
+    return __Database__generic_put_property(self, dev_name, value, self._put_device_property)
+
+def __Database__delete_device_property(self, dev_name, value):
+    """
+        delete_device_property(self, dev_name, value) -> None
+
+            Delete a the given of properties for the specified device.
+
+            Parameters :
+                - dev_name : (str) object name
+                - value : can be one of the following:
+                    1. str [in] - single property data to be deleted
+                    2. DbDatum [in] - single property data to be deleted
+                    3. DbData [in] - several property data to be deleted
+                    4. sequence<str> [in]- several property data to be deleted
+                    5. sequence<DbDatum> [in] - several property data to be deleted
+                    6. dict<str, obj> [in] - keys are property names to be deleted (values are ignored)
+                    7. dict<str, DbDatum> [in] - several DbDatum.name are property names to be deleted (keys are ignored)
+
+            Return     : None
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)"""
+    return __Database__generic_delete_property(self, dev_name, value, self._delete_device_property)
+
+def __Database__get_device_property_list(self, dev_name, wildcard, array=None):
+    """
+        get_device_property_list(self, dev_name, wildcard, array=None) -> DbData
+
+                Query the database for a list of properties defined for the
+                specified device and which match the specified wildcard.
+                If array parameter is given, it must be an object implementing de 'append'
+                method. If given, it is filled with the matching property names. If not given
+                the method returns a new DbDatum containing the matching property names.
+
+            New in PyTango 7.0.0
+
+            Parameters :
+                - dev_name : (str) device name
+                - wildcard : (str) property name wildcard
+                - array : [out] (sequence) (optional) array that
+                              will contain the matching property names.
+            Return     : if container is None, return is a new DbDatum containing the
+                         matching property names. Otherwise returns the given array
+                         filled with the property names
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device"""
+    if array is None:
+        return self._get_device_property_list(dev_name, wildcard)
+    elif isinstance(array, StdStringVector):
+        return self._get_device_property_list(dev_name, wildcard, array)
+    elif operator.isSequenceType(array) and not type(array) in types.StringTypes:
+        res = self._get_device_property_list(dev_name, wildcard)
+        for e in res: array.append(e)
+        return array
+
+def __Database__get_device_attribute_property(self, dev_name, value):
+    """
+        get_device_attribute_property(self, dev_name, value) -> dict<str, dict<str, seq<str>>>
+
+                Query the database for a list of device attribute properties for the
+                specified device. The method returns all the properties for the specified
+                attributes.
+
+            Parameters :
+                - dev_name : (string) device name
+                - value : can be one of the following:
+                    1. str [in] - single attribute properties to be fetched
+                    2. DbDatum [in] - single attribute properties to be fetched
+                    3. DbData [in,out] - several attribute properties to be fetched
+                       In this case (direct C++ API) the DbData will be filled with the property
+                       values
+                    4. sequence<str> [in] - several attribute properties to be fetched
+                    5. sequence<DbDatum> [in] - several attribute properties to be fetched
+                    6. dict<str, obj> [in,out] - keys are attribute names
+                       In this case the given dict values will be changed to contain the several
+                       attribute property values
+
+            Return     :  a dictionary which keys are the attribute names the
+                                 value associated with each key being a another
+                                 dictionary where keys are property names and value is
+                                 a DbDatum containing the property value.
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)"""
+
+    ret = None
+    if isinstance(value, DbData):
+        new_value = value
+    elif isinstance(value, DbDatum):
+        new_value = DbData()
+        new_value.append(value)
+    elif type(value) in types.StringTypes:
+        new_value = DbData()
+        new_value.append(DbDatum(value))
+    elif operator.isSequenceType(value):
+        new_value = DbData()
+        for e in value:
+            if isinstance(e, DbDatum):
+                new_value.append(e)
+            else:
+                new_value.append(DbDatum(str(e)))
+    elif operator.isMappingType(value):
+        new_value = DbData()
+        for k, v in value.iteritems():
+            if isinstance(v, DbDatum):
+                new_value.append(v)
+            else:
+                new_value.append(DbDatum(k))
+    else:
+        raise TypeError('value must be a string, PyTango.DbDatum, '\
+                        'PyTango.DbData, a sequence or a dictionary')
+
+    if ret is None: ret = {}
+
+    self._get_device_attribute_property(dev_name, new_value)
+
+    nb_items = len(new_value)
+    i = 0
+    while i < nb_items:
+        db_datum = new_value[i]
+        curr_dict = {}
+        ret[db_datum.name] = curr_dict
+        nb_props = int(db_datum[0])
+        i += 1
+        for k in xrange(nb_props):
+            db_datum = new_value[i]
+            curr_dict[db_datum.name] = db_datum.value_string
+            i += 1
+
+    return ret
+
+def __Database__put_device_attribute_property(self, dev_name, value):
+    """
+        put_device_attribute_property( self, dev_name, value) -> None
+
+                Insert or update a list of properties for the specified device.
+
+            Parameters :
+                - dev_name : (str) device name
+                - value : can be one of the following:
+                    1. DbData - several property data to be inserted
+                    2. sequence<DbDatum> - several property data to be inserted
+                    3. dict<str, dict<str, obj>> keys are attribute names and value being another
+                       dictionary which keys are the attribute property names and the value
+                       associated with each key being:
+                       3.1 seq<str>
+                       3.2 PyTango.DbDatum
+
+            Return     : None
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)"""
+    if isinstance(value, DbData):
+        pass
+    elif operator.isSequenceType(value) and not type(value) in types.StringTypes:
+        new_value = seq_2_DbData(value)
+    elif operator.isMappingType(value):
+        new_value = DbData()
+        for k1, v1 in value.iteritems():
+            attr = DbDatum(k1)
+            attr.append(str(len(v1)))
+            new_value.append(attr)
+            for k2, v2 in v1.iteritems():
+                if isinstance(v2, DbDatum):
+                    new_value.append(v2)
+                    continue
+                db_datum = DbDatum(k2)
+                if operator.isSequenceType(v2) and not type(v2) in types.StringTypes:
+                    seq_2_StdStringVector(v2, db_datum.value_string)
+                else:
+                    db_datum.value_string.append(str(v2))
+                new_value.append(db_datum)
+        value = new_value
+    else:
+        raise TypeError('value must be a PyTango.DbData,'\
+                        'a sequence<DbDatum> or a dictionary')
+    return self._put_device_attribute_property(dev_name, value)
+
+def __Database__delete_device_attribute_property(self, dev_name, value):
+    """
+        delete_device_attribute_property(self, dev_name, value) -> None
+
+                Delete a list of attribute properties for the specified device.
+
+            Parameters :
+                - devname : (string) device name
+                - propnames : can be one of the following:
+                    1. DbData [in] - several property data to be deleted
+                    2. sequence<str> [in]- several property data to be deleted
+                    3. sequence<DbDatum> [in] - several property data to be deleted
+                    3. dict<str, seq<str>> keys are attribute names and value being a list of attribute property names
+
+            Return     : None
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)"""
+
+    if isinstance(value, DbData):
+        new_value = value
+    elif operator.isSequenceType(value) and not type(value) in types.StringTypes:
+        new_value = seq_2_DbData(value)
+    elif operator.isMappingType(value):
+        new_value = DbData()
+        for k1, v1 in value.iteritems():
+            attr = DbDatum(k1)
+            attr.append(str(len(v1)))
+            new_value.append(attr)
+            for k2 in v1:
+                new_value.append(DbDatum(k2))
+    else:
+        raise TypeError('value must be a string, PyTango.DbDatum, '\
+                        'PyTango.DbData, a sequence or a dictionary')
+
+    return self._delete_device_attribute_property(dev_name, new_value)
+
+def __Database__get_class_property(self, class_name, value):
+    """
+        get_class_property(self, class_name, value) -> dict<str, seq<str>>
+
+                Query the database for a list of class properties.
+
+            Parameters :
+                - class_name : (str) class name
+                - value : can be one of the following:
+                    1. str [in] - single property data to be fetched
+                    2. PyTango.DbDatum [in] - single property data to be fetched
+                    3. PyTango.DbData [in,out] - several property data to be fetched
+                       In this case (direct C++ API) the DbData will be filled with the
+                       property values
+                    4. sequence<str> [in] - several property data to be fetched
+                    5. sequence<DbDatum> [in] - several property data to be fetched
+                    6. dict<str, obj> [in,out] - keys are property names
+                       In this case the given dict values will be changed to contain the
+                       several property values
+
+            Return     : a dictionary which keys are the property names the value
+                        associated with each key being a a sequence of strings being the
+                        property value.
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)"""
+    return __Database__generic_get_property(self, class_name, value, self._get_class_property)
+
+def __Database__put_class_property(self, class_name, value):
+    """
+        put_class_property(self, class_name, value) -> None
+
+                Insert or update a list of properties for the specified class.
+
+            Parameters :
+                - class_name : (str) class name
+                - value : can be one of the following:
+                    1. DbDatum - single property data to be inserted
+                    2. DbData - several property data to be inserted
+                    3. sequence<DbDatum> - several property data to be inserted
+                    4. dict<str, DbDatum> - keys are property names and value has data to be inserted
+                    5. dict<str, obj> - keys are property names and str(obj) is property value
+                    6. dict<str, seq<str>> - keys are property names and value has data to be inserted
+            Return     : None
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)"""
+    return __Database__generic_put_property(self, class_name, value, self._put_class_property)
+
+def __Database__delete_class_property(self, class_name, value):
+    """
+        delete_class_property(self, class_name, value) -> None
+
+                Delete a the given of properties for the specified class.
+
+            Parameters :
+                - class_name : (str) class name
+                - value : can be one of the following:
+                    1. str [in] - single property data to be deleted
+                    2. DbDatum [in] - single property data to be deleted
+                    3. DbData [in] - several property data to be deleted
+                    4. sequence<str> [in]- several property data to be deleted
+                    5. sequence<DbDatum> [in] - several property data to be deleted
+                    6. dict<str, obj> [in] - keys are property names to be deleted
+                                             (values are ignored)
+                    7. dict<str, DbDatum> [in] - several DbDatum.name are property names
+                                                 to be deleted (keys are ignored)
+            Return     : None
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)"""
+    return __Database__generic_delete_property(self, class_name, value, self._delete_class_property)
+
+def __Database__get_class_attribute_property(self, class_name, value):
+    """
+        get_class_attribute_property( self, class_name, value) -> dict<str, dict<str, seq<str>>
+
+                Query the database for a list of class attribute properties for the
+                specified class. The method returns all the properties for the specified
+                attributes.
+
+            Parameters :
+                - class_name : (str) class name
+                - propnames : can be one of the following:
+                    1. str [in] - single attribute properties to be fetched
+                    2. DbDatum [in] - single attribute properties to be fetched
+                    3. DbData [in,out] - several attribute properties to be fetched
+                       In this case (direct C++ API) the DbData will be filled with the property
+                       values
+                    4. sequence<str> [in] - several attribute properties to be fetched
+                    5. sequence<DbDatum> [in] - several attribute properties to be fetched
+                    6. dict<str, obj> [in,out] - keys are attribute names
+                       In this case the given dict values will be changed to contain the several
+                       attribute property values
+
+            Return     : a dictionary which keys are the attribute names the
+                         value associated with each key being a another
+                         dictionary where keys are property names and value is
+                         a sequence of strings being the property value.
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)"""
+
+    ret = None
+    if isinstance(value, DbData):
+        new_value = value
+    elif isinstance(value, DbDatum):
+        new_value = DbData()
+        new_value.append(value)
+    elif type(value) in types.StringTypes:
+        new_value = DbData()
+        new_value.append(DbDatum(value))
+    elif operator.isSequenceType(value):
+        new_value = DbData()
+        for e in value:
+            if isinstance(e, DbDatum):
+                new_value.append(e)
+            else:
+                new_value.append(DbDatum(str(e)))
+    elif operator.isMappingType(value):
+        new_value = DbData()
+        for k, v in value.iteritems():
+            if isinstance(v, DbDatum):
+                new_value.append(v)
+            else:
+                new_value.append(DbDatum(k))
+    else:
+        raise TypeError('value must be a string, PyTango.DbDatum, '\
+                        'PyTango.DbData, a sequence or a dictionary')
+
+    self._get_class_attribute_property(class_name, new_value)
+
+    if ret is None: ret = {}
+
+    nb_items = len(new_value)
+    i = 0
+    while i < nb_items:
+        db_datum = new_value[i]
+        curr_dict = {}
+        ret[db_datum.name] = curr_dict
+        nb_props = int(db_datum[0])
+        i += 1
+        for k in xrange(nb_props):
+            db_datum = new_value[i]
+            curr_dict[db_datum.name] = db_datum.value_string
+            i += 1
+
+    return ret
+
+def __Database__put_class_attribute_property(self, class_name, value):
+    """
+        put_class_attribute_property(self, class_name, value) -> None
+
+                Insert or update a list of properties for the specified class.
+
+            Parameters :
+                - class_name : (str) class name
+                - propdata : can be one of the following:
+                    1. PyTango.DbData - several property data to be inserted
+                    2. sequence<DbDatum> - several property data to be inserted
+                    3. dict<str, dict<str, obj>> keys are attribute names and value
+                       being another dictionary which keys are the attribute property
+                       names and the value associated with each key being:
+                       3.1 seq<str>
+                       3.2 PyTango.DbDatum
+
+            Return     : None
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)"""
+
+    if isinstance(value, DbData):
+        pass
+    elif operator.isSequenceType(value) and not type(value) in types.StringTypes:
+        new_value = seq_2_DbData(value)
+    elif operator.isMappingType(value):
+        new_value = DbData()
+        for k1, v1 in value.iteritems():
+            attr = DbDatum(k1)
+            attr.append(str(len(v1)))
+            new_value.append(attr)
+            for k2, v2 in v1.iteritems():
+                if isinstance(v2, DbDatum):
+                    new_value.append(v2)
+                    continue
+                db_datum = DbDatum(k2)
+                if operator.isSequenceType(v2) and not type(v2) in types.StringTypes:
+                    seq_2_StdStringVector(v2, db_datum.value_string)
+                else:
+                    db_datum.value_string.append(str(v2))
+                new_value.append(db_datum)
+        value = new_value
+    else:
+        raise TypeError('value must be a PyTango.DbData,'\
+                        'a sequence<DbDatum> or a dictionary')
+    return self._put_class_attribute_property(class_name, value)
+
+def __Database__delete_class_attribute_property(self, class_name, value):
+    """
+        delete_class_attribute_property(self, class_name, value) -> None
+
+                Delete a list of attribute properties for the specified class.
+
+            Parameters :
+                - class_name : (str) class name
+                - propnames : can be one of the following:
+                    1. DbData [in] - several property data to be deleted
+                    2. sequence<str> [in]- several property data to be deleted
+                    3. sequence<DbDatum> [in] - several property data to be deleted
+                    4. dict<str, seq<str>> keys are attribute names and value being a
+                       list of attribute property names
+            Return     : None
+
+            Throws     : ConnectionFailed, CommunicationFailed
+                         DevFailed from device (DB_SQLError)"""
+
+    if isinstance(value, DbData):
+        new_value = value
+    elif operator.isSequenceType(value) and not type(value) in types.StringTypes:
+        new_value = seq_2_DbData(value)
+    elif operator.isMappingType(value):
+        new_value = DbData()
+        for k1, v1 in value.iteritems():
+            attr = DbDatum(k1)
+            attr.append(str(len(v1)))
+            new_value.append(attr)
+            for k2 in v1:
+                new_value.append(DbDatum(k2))
+    else:
+        raise TypeError('value must be a DbDatum, DbData, '\
+                        'a sequence or a dictionary')
+
+    return self._delete_class_attribute_property(class_name, new_value)
+
+def __Database__get_service_list(self, filter='.*'):
+    import re
+    data = self.get_property('CtrlSystem', 'Services')
+    res = {}
+    filter_re = re.compile(filter)
+    for service in data['Services']:
+        service_name, service_value = service.split(':')
+        if not filter_re.match(service_name) is None:
+            res[service_name] = service_value
+    return res
+    
+def __Database__str(self):
+    return "Database(%s, %s)" % (self.get_db_host(), self.get_db_port())
+
+def __init_Database():
+    Database.add_server                       = __Database__add_server
+    Database.export_server                    = __Database__export_server
+    Database.put_property                     = __Database__put_property
+    Database.get_property                     = __Database__get_property
+    Database.get_property_forced              = __Database__get_property_forced
+    Database.delete_property                  = __Database__delete_property
+    Database.get_device_property              = __Database__get_device_property
+    Database.put_device_property              = __Database__put_device_property
+    Database.delete_device_property           = __Database__delete_device_property
+    Database.get_device_property_list         = __Database__get_device_property_list
+    Database.get_device_attribute_property    = __Database__get_device_attribute_property
+    Database.put_device_attribute_property    = __Database__put_device_attribute_property
+    Database.delete_device_attribute_property = __Database__delete_device_attribute_property
+    Database.get_class_property               = __Database__get_class_property
+    Database.put_class_property               = __Database__put_class_property
+    Database.delete_class_property            = __Database__delete_class_property
+    Database.get_class_attribute_property     = __Database__get_class_attribute_property
+    Database.put_class_attribute_property     = __Database__put_class_attribute_property
+    Database.delete_class_attribute_property  = __Database__delete_class_attribute_property
+    Database.get_service_list                 = __Database__get_service_list
+    Database.__str__                          = __Database__str
+    Database.__repr__                         = __Database__str
+    
+def __doc_Database():
+    def document_method(method_name, desc, append=True):
+        return __document_method(Database, method_name, desc, append)
+
+    Database.__doc__ = """
+    Database is the high level Tango object which contains the link to the static database.
+    Database provides methods for all database commands : get_device_property(), put_device_property(), info(), etc..
+    To create a Database, use the default constructor.
+    Example:
+        db = Database()
+    The constructor uses the TANGO_HOST env. variable to determine which instance of the Database to connect to."""
+
+    document_method("write_filedatabase", """
+    write_filedatabase(self) -> None
+
+            Force a write to the file if using a file based database.
+
+        Parameters : None
+        Return     : None
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("reread_filedatabase", """
+    reread_filedatabase(self) -> None
+
+            Force a complete refresh over the database if using a file based database.
+
+        Parameters : None
+        Return     : None
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("build_connection", """
+    build_connection(self) -> None
+
+            Tries to build a connection to the Database server.
+
+        Parameters : None
+        Return     : None
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("check_tango_host", """
+    check_tango_host(self, tango_host_env) -> None
+
+            Check the TANGO_HOST environment variable syntax and extract
+            database server host(s) and port(s) from it.
+
+        Parameters :
+            - tango_host_env : (str) The TANGO_HOST env. variable value
+        Return     : None
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("check_access_control", """
+    check_access_control(self, dev_name) -> AccessControlType
+
+            Check the access for the given device for this client.
+
+        Parameters :
+            - dev_name : (str) device name
+        Return     : the access control type as a AccessControlType object
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("is_control_access_checked", """
+    is_control_access_checked(self) -> bool
+
+            Returns True if control access is checked or False otherwise.
+
+        Parameters : None
+        Return     : (bool) True if control access is checked or False
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("set_access_checked", """
+    set_access_checked(self, val) -> None
+
+            Sets or unsets the control access check.
+
+        Parameters :
+            - val : (bool) True to set or False to unset the access control
+        Return     : None
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("get_access_except_errors", """
+    get_access_except_errors(self) -> DevErrorList
+
+            Returns a reference to the conctrol access exceptions.
+
+        Parameters : None
+        Return     : DevErrorList
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("get_info", """
+    get_info(self) -> str
+
+            Query the database for some general info about the tables.
+
+        Parameters : None
+        Return     : a multiline string
+    """ )
+
+    document_method("get_host_list", """
+    get_host_list(self) -> DbDatum
+    get_host_list(self, wildcard) -> DbDatum
+
+            Returns the list of all host names registered in the database.
+
+        Parameters :
+            - wildcard : (str) (optional) wildcard (eg: 'l-c0*')
+        Return     : DbDatum with the list of registered host names
+    """ )
+
+    document_method("get_services", """
+    get_services(self, serv_name, inst_name) -> DbDatum
+
+            Query database for specified services.
+
+        Parameters :
+            - serv_name : (str) service name
+            - inst_name : (str) instance name (can be a wildcard character ('*'))
+        Return     : DbDatum with the list of available services
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("register_service", """
+    register_service(self, serv_name, inst_name, dev_name) -> None
+
+            Register the specified service wihtin the database.
+
+        Parameters :
+            - serv_name : (str) service name
+            - inst_name : (str) instance name
+            - dev_name : (str) device name
+        Return     : None
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("unregister_service", """
+    unregister_service(self, serv_name, inst_name) -> None
+
+            Unregister the specified service from the database.
+
+        Parameters :
+            - serv_name : (str) service name
+            - inst_name : (str) instance name
+        Return     : None
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("add_device", """
+    add_device(self, dev_info) -> None
+
+            Add a device to the database. The device name, server and class
+            are specified in the DbDevInfo structure
+
+            Example :
+                dev_info = DbDevInfo()
+                dev_info.name = 'my/own/device'
+                dev_info.class = 'MyDevice'
+                dev_info.server = 'MyServer/test'
+                db.add_device(dev_info)
+
+        Parameters :
+            - dev_info : (DbDevInfo) device information
+        Return     : None
+    """ )
+
+    document_method("delete_device", """
+    delete_device(self, dev_name) -> None
+
+            Delete the device of the specified name from the database.
+
+        Parameters :
+            - dev_name : (str) device name
+        Return     : None
+    """ )
+
+    document_method("import_device", """
+    import_device(self, dev_name) -> DbDevImportInfo
+
+            Query the databse for the export info of the specified device.
+
+            Example :
+                dev_imp_info = db.import_device('my/own/device')
+                print dev_imp_info.name
+                print dev_imp_info.exported
+                print dev_imp_info.ior
+                print dev_imp_info.version
+
+        Parameters :
+            - dev_name : (str) device name
+        Return     : DbDevImportInfo
+    """ )
+
+    document_method("export_device", """
+    export_device(self, dev_export) -> None
+
+            Update the export info for this device in the database.
+
+            Example :
+                dev_export = DbDevExportInfo()
+                dev_export.name = 'my/own/device'
+                dev_export.ior = <the real ior>
+                dev_export.host = <the host>
+                dev_export.version = '3.0'
+                dev_export.pid = '....'
+                db.export_device(dev_export)
+
+        Parameters :
+            - dev_export : (DbDevExportInfo) export information
+        Return     : None
+    """ )
+
+    document_method("unexport_device", """
+    unexport_device(self, dev_name) -> None
+
+            Mark the specified device as unexported in the database
+
+            Example :
+               db.unexport_device('my/own/device')
+
+        Parameters :
+            - dev_name : (str) device name
+        Return     : None
+    """ )
+
+    document_method("get_device_name", """
+    get_device_name(self, serv_name, class_name) -> DbDatum
+
+            Query the database for a list of devices served by a server for
+            a given device class
+
+        Parameters :
+            - serv_name : (str) server name
+            - class_name : (str) device class name
+        Return     : DbDatum with the list of device names
+    """ )
+
+    document_method("get_device_exported", """
+    get_device_exported(self, filter) -> DbDatum
+
+            Query the database for a list of exported devices whose names
+            satisfy the supplied filter (* is wildcard for any character(s))
+
+        Parameters :
+            - filter : (str) device name filter (wildcard)
+        Return     : DbDatum with the list of exported devices
+    """ )
+
+    document_method("get_device_domain", """
+    get_device_domain(self, wildcard) -> DbDatum
+
+            Query the database for a list of of device domain names which
+            match the wildcard provided (* is wildcard for any character(s)).
+            Domain names are case insensitive.
+
+        Parameters :
+            - wildcard : (str) domain filter
+        Return     : DbDatum with the list of device domain names
+    """ )
+
+    document_method("get_device_family", """
+    get_device_family(self, wildcard) -> DbDatum
+
+            Query the database for a list of of device family names which
+            match the wildcard provided (* is wildcard for any character(s)).
+            Family names are case insensitive.
+
+        Parameters :
+            - wildcard : (str) family filter
+        Return     : DbDatum with the list of device family names
+    """ )
+
+    document_method("get_device_member", """
+    get_device_member(self, wildcard) -> DbDatum
+
+            Query the database for a list of of device member names which
+            match the wildcard provided (* is wildcard for any character(s)).
+            Member names are case insensitive.
+
+        Parameters :
+            - wildcard : (str) member filter
+        Return     : DbDatum with the list of device member names
+    """ )
+
+    document_method("get_device_alias", """
+    get_device_alias(self, alias) -> str
+
+            Get the device name from an alias.
+
+        Parameters :
+            - alias : (str) alias
+        Return     : device name
+    """ )
+
+    document_method("get_alias", """
+    get_alias(self, alias) -> str
+
+            Get the device alias name from its name.
+
+        Parameters :
+            - alias : (str) device name
+        Return     : alias
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("get_device_alias_list", """
+    get_device_alias_list(self, filter) -> DbDatum
+
+            Get device alias list. The parameter alias is a string to filter
+            the alias list returned. Wildcard (*) is supported.
+
+        Parameters :
+            - filter : (str) a string with the alias filter (wildcard (*) is supported)
+        Return     : DbDatum with the list of device names
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("get_class_for_device", """
+    get_class_for_device(self, dev_name) -> str
+
+            Return the class of the specified device.
+
+        Parameters :
+            - dev_name : (str) device name
+        Return     : a string containing the device class
+    """ )
+
+    document_method("get_class_inheritance_for_device", """
+    get_class_inheritance_for_device(self, dev_name) -> DbDatum
+
+            Return the class inheritance scheme of the specified device.
+
+        Parameters :
+            - devn_ame : (str) device name
+        Return     : DbDatum with the inheritance class list
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("get_class_for_device", """
+    get_class_for_device(self, dev_name) -> str
+
+            Return the class of the specified device.
+
+        Parameters :
+            - dev_name : (str) device name
+        Return     : a string containing the device class
+    """ )
+
+    document_method("get_device_exported_for_class", """
+    get_device_exported_for_class(self, class_name) -> DbDatum
+
+            Query database for list of exported devices for the specified class.
+
+        Parameters :
+            - class_name : (str) class name
+        Return     : DbDatum with the list of exported devices for the
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("put_device_alias", """
+    put_device_alias(self, dev_name, alias) -> None
+
+            Query database for list of exported devices for the specified class.
+
+        Parameters :
+            - dev_name : (str) device name
+            - alias : (str) alias name
+        Return     : None
+    """ )
+
+    document_method("delete_device_alias", """
+    delete_device_alias(self, alias) -> void
+
+            Delete a device alias
+
+        Parameters :
+            - alias : (str) alias name
+        Return     : None
+    """ )
+
+    document_method("_add_server", """
+    _add_server(self, serv_name, dev_info) -> None
+
+            Add a a group of devices to the database.
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - serv_name : (str) server name
+            - dev_info : (DbDevInfos) server device(s) information
+        Return     : None
+    """ )
+
+    document_method("delete_server", """
+    delete_server(self, server) -> None
+
+            Delete the device server and its associated devices from database.
+
+        Parameters :
+            - server : (str) name of the server to be deleted with
+                       format: <server name>/<instance>
+        Return     : None
+    """ )
+
+    document_method("_export_server", """
+    _export_server(self, dev_info) -> None
+
+            Export a group of devices to the database.
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - dev_info : (DbDevExportInfos) device(s) to export information
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("unexport_server", """
+    unexport_server(self, server) -> None
+
+            Mark all devices exported for this server as unexported.
+
+        Parameters :
+            - server : (str) name of the server to be unexported with
+                       format: <server name>/<instance>
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("get_server_info", """
+    get_server_info(self, server) -> DbServerInfo
+
+            Query the database for server information.
+
+        Parameters :
+            - server : (str) name of the server to be unexported with
+                       format: <server name>/<instance>
+        Return     : DbServerInfo with server information
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("put_server_info", """
+    put_server_info(self, info) -> None
+
+            Add/update server information in the database.
+
+        Parameters :
+            - info : (DbServerInfo) new server information
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("delete_server_info", """
+    delete_server_info(self, server) -> None
+
+            Delete server information of the specifed server from the database.
+
+        Parameters :
+            - server : (str) name of the server to be deleted with
+                       format: <server name>/<instance>
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("get_server_class_list", """
+    get_server_class_list(self, server) -> DbDatum
+
+            Query the database for a list of classes instancied by the
+            specified server. The DServer class exists in all TANGO servers
+            and for this reason this class is removed from the returned list.
+
+        Parameters :
+            - server : (str) name of the server to be deleted with
+                       format: <server name>/<instance>
+        Return     : DbDatum containing list of class names instanciated by
+                     the specified server
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("get_server_name_list", """
+    get_server_name_list(self) -> DbDatum
+
+            Return the list of all server names registered in the database.
+
+        Parameters : None
+        Return     : DbDatum containing list of server names
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("get_instance_name_list", """
+    get_instance_name_list(self, serv_name) -> DbDatum
+
+            Return the list of all instance names existing in the database for the specifed server.
+
+        Parameters :
+            - serv_name : (str) server name with format <server name>
+        Return     : DbDatum containing list of instance names for the specified server
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("get_server_list", """
+    get_server_list(self) -> DbDatum
+    get_server_list(self, wildcard) -> DbDatum
+
+            Return the list of all servers registered in the database.
+            If wildcard parameter is given, then the the list of servers registred on the
+            specified host (we refer 'host' in the context of tango device, i.e. following
+            the tango naming convention 'host/family/member') is returned
+
+        Parameters :
+            - wildcard : (str) host wildcard
+        Return     : DbDatum containing list of registered servers
+    """ )
+
+    document_method("get_host_server_list", """
+    get_host_server_list(self, host_name) -> DbDatum
+
+            Query the database for a list of servers registred on the specified host.
+
+        Parameters :
+            - host_name : (str) host name
+        Return     : DbDatum containing list of servers for the specified host
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("get_device_class_list", """
+    get_device_class_list(self, server) -> DbDatum
+
+            Query the database for a list of devices and classes served by
+            the specified server. Return a list with the following structure:
+            [device name, class name, device name, class name, ...]
+
+        Parameters :
+            - server : (str) name of the server with format: <server name>/<instance>
+        Return     : DbDatum containing list with the following structure:
+                     [device_name, class name]
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("_get_property", """
+    _get_property(self, obj_name, props) -> None
+
+            Query the database for a list of object (i.e non-device)
+            properties. The property names are specified by the
+            DbData (seq<DbDatum>) structures. The method returns the
+            properties in the same DbDatum structures
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - obj_name : (str) object name
+            - props [in, out] : (DbData) property names
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("_get_property_forced", """
+    _get_property_forced(self, obj_name, props) -> None
+
+            Query the database for a list of object (i.e non-device)
+            properties. The property names are specified by the
+            DbData (seq<DbDatum>) structures. The method returns the
+            properties in the same DbDatum structures
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - obj_name : (str) object name
+            - props [in, out] : (DbData) property names
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("_delete_property", """
+    _delete_property(self, obj_name, props) -> None
+
+            Delete a list of properties for the specified object.
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - obj_name : (str) object name
+            - props : (DbData) property names
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("get_property_history", """
+    get_property_history(self, obj_name, prop_name) -> DbHistoryList
+
+            Get the list of the last 10 modifications of the specifed object
+            property. Note that propname can contain a wildcard character
+            (eg: 'prop*')
+
+        Parameters :
+            - serv_name : (str) server name
+            - prop_name : (str) property name
+        Return     : DbHistoryList containing the list of modifications
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("get_object_list", """
+    get_object_list(self, wildcard) -> DbDatum
+
+            Query the database for a list of object (free properties) for
+            which properties are defined and which match the specified
+            wildcard.
+
+        Parameters :
+            - wildcard : (str) object wildcard
+        Return     : DbDatum containing the list of object names matching the given wildcard
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("get_object_property_list", """
+    get_object_property_list(self, obj_name, wildcard) -> DbDatum
+
+            Query the database for a list of properties defined for the
+            specified object and which match the specified wildcard.
+
+        Parameters :
+            - obj_name : (str) object name
+            - wildcard : (str) property name wildcard
+        Return     : DbDatum with list of properties defined for the specified
+                     object and which match the specified wildcard
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("_get_device_property", """
+    _get_device_property(self, dev_name, props) -> None
+
+            Query the database for a list of device properties for the
+            specified device. The property names are specified by the
+            DbData (seq<DbDatum>) structures. The method returns the
+            properties in the same DbDatum structures
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - dev_name : (str) device name
+            - props : (DbData) property names
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("_put_device_property", """
+    _put_device_property(self, dev_name, props) -> None
+
+            Insert or update a list of properties for the specified device.
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - dev_name : (str) device name
+            - props : (DbData) property data
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("_delete_device_property", """
+    _delete_device_property(self, dev_name, props) -> None
+
+            Delete a list of properties for the specified device.
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - dev_name : (str) device name
+            - props : (DbData) property names to be deleted
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("get_device_property_history", """
+    get_device_property_history(self, dev_name, prop_name) -> DbHistoryList
+
+            Get the list of the last 10 modifications of the specified device
+            property. Note that propname can contain a wildcard character
+            (eg: 'prop*').
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - serv_name : (str) server name
+            - prop_name : (str) property name
+        Return     : DbHistoryList containing the list of modifications
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("_get_device_property_list", """
+    _get_device_property_list(self, dev_name, wildcard) -> DbDatum
+    _get_device_property_list(self, dev_name, wildcard, container) -> None
+
+            Query the database for a list of properties defined for the
+            specified device and which match the specified wildcard.
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - dev_name : (str) device name
+            - wildcard : (str) property name wildcard
+            - container [out] : (StdStringVector) array that will contain the matching
+                                property names
+        Return     : DbDatum containing the list of property names or None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("_get_device_attribute_property", """
+    _get_device_attribute_property(self, dev_name, props) -> None
+
+            Query the database for a list of device attribute properties for
+            the specified device. The attribute names are specified by the
+            DbData (seq<DbDatum>) structures. The method returns all the
+            properties for the specified attributes in the same DbDatum structures.
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - dev_name : (str) device name
+            - props [in, out] : (DbData) attribute names
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("_put_device_attribute_property", """
+    _put_device_attribute_property(self, dev_name, props) -> None
+
+            Insert or update a list of attribute properties for the specified device.
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - dev_name : (str) device name
+            - props : (DbData) property data
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("_delete_device_attribute_property", """
+    _delete_device_attribute_property(self, dev_name, props) -> None
+
+            Delete a list of attribute properties for the specified device.
+            The attribute names are specified by the vector of DbDatum structures. Here
+            is an example of how to delete the unit property of the velocity attribute of
+            the id11/motor/1 device using this method :
+
+            db_data = PyTango.DbData();
+            db_data.append(DbDatum("velocity"));
+            db_data.append(DbDatum("unit"));
+            db.delete_device_attribute_property("id11/motor/1", db_data);
+
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - serv_name : (str) server name
+            - props : (DbData) attribute property data
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("get_device_attribute_property_history", """
+    get_device_attribute_property_history(self, dev_name, att_name, prop_name) -> DbHistoryList
+
+            Get the list of the last 10 modifications of the specified device
+            attribute property. Note that propname and devname can contain a
+            wildcard character (eg: 'prop*').
+
+        Parameters :
+            - devn_ame : (str) device name
+            - attn_ame : (str) attribute name
+            - prop_name : (str) property name
+        Return     : DbHistoryList containing the list of modifications
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("_get_class_property", """
+    _get_class_property(self, class_name, props) -> None
+
+            Query the database for a list of class properties. The property
+            names are specified by the DbData (seq<DbDatum>) structures.
+            The method returns the properties in the same DbDatum structures.
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - class_name : (str) class name
+            - props [in, out] : (DbData) property names
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("_put_class_property", """
+    _put_class_property(self, class_name, props) -> None
+
+            Insert or update a list of properties for the specified class.
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - class_name : (str) class name
+            - props : (DbData) property data to be inserted
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("_delete_class_property", """
+    _delete_class_property(self, class_name, props) -> None
+
+            Delete a list of properties for the specified class.
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - class_name : (str) class name
+            - props  : (DbData) property names
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("get_class_property_history", """
+    get_class_property_history(self, class_name, prop_name) -> DbHistoryList
+
+            Get the list of the last 10 modifications of the specified class
+            property. Note that propname can contain a wildcard character
+            (eg: 'prop*').
+
+        Parameters :
+            - class_name : (str) class name
+            - prop_name : (str) property name
+        Return     : DbHistoryList containing the list of modifications
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("get_class_list", """
+    get_class_list(self, wildcard) -> DbDatum
+
+            Query the database for a list of classes which match the specified wildcard
+
+        Parameters :
+            - wildcard : (str) class wildcard
+        Return     : DbDatum containing the list of matching classes
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("get_class_property_list", """
+    get_class_property_list(self, class_name) -> DbDatum
+
+            Query the database for a list of properties defined for the specified class.
+
+        Parameters :
+            - class_name : (str) class name
+        Return     : DbDatum containing the list of properties for the specified class
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("_get_class_attribute_property", """
+    _get_class_attribute_property(self, class_name, props) -> None
+
+            Query the database for a list of class attribute properties for
+            the specified objec. The attribute names are returned with the
+            number of properties specified as their value. The first DbDatum
+            element of the returned DbData vector contains the first
+            attribute name and the first attribute property number. The
+            following DbDatum element contains the first attribute property
+            name and property values.
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - class_name : (str) class name
+            - props [in,out] : (DbData) property names
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("_put_class_attribute_property", """
+    _put_class_attribute_property(self, class_name, props) -> None
+
+            Insert or update a list of attribute properties for the specified class.
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - class_name : (str) class name
+            - props : (DbData) property data
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("get_class_attribute_property_history", """
+    get_class_attribute_property_history(self, dev_name, attr_name, prop_name) -> DbHistoryList
+
+            Delete a list of properties for the specified class.
+            This corresponds to the pure C++ API call.
+
+        Parameters :
+            - dev_name : (str) device name
+            - attr_name : (str) attribute name
+            - prop_name : (str) property name
+        Return     : DbHistoryList containing the list of modifications
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("get_class_attribute_list", """
+    get_class_attribute_list(self, class_name, wildcard) -> DbDatum
+
+            Query the database for a list of attributes defined for the specified
+            class which match the specified wildcard.
+
+        Parameters :
+            - class_name : (str) class name
+            - wildcard : (str) attribute name
+        Return     : DbDatum containing the list of matching attributes for the given class
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("get_attribute_alias", """
+    get_attribute_alias(self, alias) -> str
+
+            Get the full attribute name from an alias.
+
+        Parameters :
+            - alias : (str) attribute alias
+        Return     :  full attribute name
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("get_attribute_alias_list", """
+    get_attribute_alias_list(self, filter) -> DbDatum
+
+            Get attribute alias list. The parameter alias is a string to
+            filter the alias list returned. Wildcard (*) is supported. For
+            instance, if the string alias passed as the method parameter
+            is initialised with only the * character, all the defined
+            attribute alias will be returned. If there is no alias with the
+            given filter, the returned array will have a 0 size.
+
+        Parameters :
+            - filter : (str) attribute alias filter
+        Return     : DbDatum containing the list of matching attribute alias
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("put_attribute_alias", """
+    put_attribute_alias(self, attr_name, alias) -> None
+
+            Set an alias for an attribute name. The attribute alias is
+            specified by aliasname and the attribute name is specifed by
+            attname. If the given alias already exists, a DevFailed exception
+            is thrown.
+
+        Parameters :
+            - attr_name : (str) full attribute name
+            - alias : (str) alias
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("delete_attribute_alias", """
+    delete_attribute_alias(self, alias) -> None
+
+            Remove the alias associated to an attribute name.
+
+        Parameters :
+            - alias : (str) alias
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+    """ )
+
+    document_method("export_event", """
+    export_event(self, event_data) -> None
+
+            Export an event to the database.
+
+        Parameters :
+            - eventdata : (sequence<str>) event data (same as DbExportEvent Database command)
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("unexport_event", """
+    export_event(self, event) -> None
+
+            Export an event to the database.
+
+        Parameters :
+            - event : (str) event
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
+
+        New in PyTango 7.0.0
+    """ )
+
+def __doc_DbDatum():
+    def document_method(method_name, desc, append=True):
+        return __document_method(DbDatum, method_name, desc, append)
+
+    DbDatum.__doc__ = """
+    A single database value which has a name, type, address and value
+    and methods for inserting and extracting C++ native types. This is
+    the fundamental type for specifying database properties. Every
+    property has a name and has one or more values associated with it.
+    A status flag indicates if there is data in the DbDatum object or
+    not. An additional flag allows the user to activate exceptions.
+
+    Note: DbDatum is extended to support the python sequence API.
+          This way the DbDatum behaves like a sequence of strings.
+          This allows the user to work with a DbDatum as if it was
+          working with the old list of strings.
+
+    New in PyTango 7.0.0"""
+
+    document_method("size", """
+    size(self) -> int
+
+            Returns the number of separate elements in the value.
+
+        Parameters : None
+        Return     : the number of separate elements in the value.
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("is_empty", """
+    is_empty(self) -> bool
+
+            Returns True or False depending on whether the
+            DbDatum object contains data or not. It can be used to test
+            whether a property is defined in the database or not.
+
+        Parameters : None
+        Return     : (bool) True if no data or False otherwise.
+
+        New in PyTango 7.0.0
+    """ )
+
+def __doc_DbDevExportInfo():
+    DbDevExportInfo.__doc__ = """
+    import info for a device (should be retrived from the database) with
+    the following members:
+        - name : device name
+        - ior : CORBA reference of the device
+        - host : name of the computer hosting the server
+        - version : str
+        - pid : process identifier"""
+
+def __doc_DbDevImportInfo():
+    DbDevImportInfo.__doc__ = """
+    import info for a device (should be retrived from the database) with
+    the following members:
+        - name : device name
+        - exported : 1 if device is running, 0 else
+        - ior : CORBA reference of the device
+        - version : str"""
+
+def __doc_DbDevInfo():
+    DbDevInfo.__doc__ = """
+    A structure containing available information for a device with
+    the following members:
+        - name : str
+        - _class : str
+        - server : str"""
+
+def __doc_DbHistory():
+    def document_method(method_name, desc, append=True):
+        return __document_method(DbHistory, method_name, desc, append)
+
+    DbHistory.__doc__ = """
+    A structure containing the modifications of a property. No public members."""
+
+    document_method("get_name", """
+    get_name(self) -> str
+
+            Returns the property name.
+
+        Parameters : None
+        Return     : (str) property name
+    """ )
+
+    document_method("get_attribute_name", """
+    get_attribute_name(self) -> str
+
+            Returns the attribute name (empty for object properties or device properties)
+
+        Parameters : None
+        Return     : (str) attribute name
+    """ )
+
+    document_method("get_date", """
+    get_date(self) -> str
+
+            Returns the update date
+
+        Parameters : None
+        Return     : (str) update date
+    """ )
+
+    document_method("get_value", """
+    get_value(self) -> DbDatum
+
+            Returns a COPY of the property value
+
+        Parameters : None
+        Return     : (DbDatum) a COPY of the property value
+    """ )
+
+    document_method("is_deleted", """
+    is_deleted(self) -> bool
+
+            Returns True if the property has been deleted or False otherwise
+
+        Parameters : None
+        Return     : (bool) True if the property has been deleted or False otherwise
+    """ )
+
+def __doc_DbServerInfo():
+    DbServerInfo.__doc__ = """
+    A structure containing available information for a device server with
+    the following members:
+        - name : str
+        - host : str
+        - mode : str
+        - level : str"""
+
+def init(doc=True):
+    __init_DbDatum()
+    if doc:
+        __doc_DbDatum()
+    
+    __init_Database()
+    if doc:
+        __doc_Database()
+        __doc_DbDevExportInfo()
+        __doc_DbDevImportInfo()
+        __doc_DbDevInfo()
+        __doc_DbHistory()
+        __doc_DbServerInfo()
+
diff --git a/PyTango/device_attribute.py b/PyTango/device_attribute.py
new file mode 100644
index 0000000..f18f072
--- /dev/null
+++ b/PyTango/device_attribute.py
@@ -0,0 +1,118 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = []
+
+__docformat__ = "restructuredtext"
+
+import copy
+
+from utils import document_method as __document_method
+from utils import document_enum as __document_enum
+from _PyTango import DeviceAttribute, ExtractAs
+
+def __DeviceAttribute__get_data(self):
+    return self.get_data_raw().extract()
+
+def __DeviceAttribute__init(self, da=None):
+    DeviceAttribute.__init_orig(self)
+    if da is not None:
+        try: self.value = copy.deepcopy(da.value)
+        except: pass
+        try: self.w_value = copy.deepcopy(da.w_value)
+        except: pass
+        try: self.scalar_w_value = da.scalar_w_value
+        except: pass
+        self.type = da.type
+        self.is_empty = da.is_empty
+        self.has_failed = da.has_failed
+
+def __doc_DeviceAttribute():
+    def document_method(method_name, desc, append=True):
+        return __document_method(DeviceAttribute, method_name, desc, append)
+
+    DeviceAttribute.__doc__ = """
+        This is the fundamental type for RECEIVING data from device attributes.
+
+        It contains several fields. The most important ones depend on the
+        ExtractAs method used to get the value. Normally they are:
+        
+            - value   : Normal scalar value or numpy array of values.
+            - w_value : The write part of the attribute.
+            
+        See other ExtractAs for different possibilities. There are some more
+        fields, these really fixed:
+        
+            - name        : (str)
+            - data_format : (AttrDataFormat) Attribute format
+            - quality     : (AttrQuality)
+            - time        : (TimeVal)
+            - dim_x       : (int) attribute dimension x
+            - dim_y       : (int) attribute dimension y
+            - w_dim_x     : (int) attribute written dimension x
+            - w_dim_y     : (int) attribute written dimension y
+            - r_rimension : (tuple<int,int>) Attribute read dimensions.
+            - w_dimension : (tuple<int,int>) Attribute written dimensions.
+            - nb_read     : (int) attribute read total length
+            - nb_written  : (int) attribute written total length
+            
+
+        And two methods:
+            - get_date
+            - get_err_stack
+    """
+
+    document_method("get_date", """
+    get_date(self) -> TimeVal
+
+            Get the time at which the attribute was read by the server.
+            
+            Note: It's the same as reading the "time" attribute.
+        
+        Parameters : None
+        Return     : (TimeVal) The attribute read timestamp.
+    """ )
+
+    document_method("get_err_stack", """
+    get_err_stack(self) -> sequence<DevError>
+
+            Returns the error stack reported by the server when the
+            attribute was read.
+
+        Parameters : None
+        Return     : (sequence<DevError>)
+    """ )
+
+def __init_DeviceAttribute():
+    DeviceAttribute.__init_orig = DeviceAttribute.__init__
+    DeviceAttribute.__init__ = __DeviceAttribute__init
+    DeviceAttribute.ExtractAs = ExtractAs
+    pass
+
+def init(doc=True):
+    __init_DeviceAttribute()
+    if doc:
+        __doc_DeviceAttribute()
diff --git a/PyTango/device_class.py b/PyTango/device_class.py
new file mode 100644
index 0000000..ea44caf
--- /dev/null
+++ b/PyTango/device_class.py
@@ -0,0 +1,910 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = [ "DeviceClass" ]
+
+__docformat__ = "restructuredtext"
+
+import types
+import operator
+
+from _PyTango import Except, DevFailed
+from _PyTango import _DeviceClass, Database
+from _PyTango import CmdArgType, AttrDataFormat, AttrWriteType, DispLevel
+from _PyTango import UserDefaultAttrProp
+
+from pyutil import Util
+
+from utils import DbData_2_dict, seqStr_2_obj, obj_2_str, is_array
+from utils import document_method as __document_method
+
+from globals import get_classes, get_class, get_class_by_class
+from globals import get_constructed_classes, get_constructed_class, get_constructed_class_by_class
+
+class PropUtil:
+    """An internal Property util class"""
+
+    scalar_int_types = (CmdArgType.DevShort, CmdArgType.DevUShort,
+        CmdArgType.DevInt, CmdArgType.DevLong, CmdArgType.DevULong,)
+
+    scalar_long_types = (CmdArgType.DevLong64, CmdArgType.DevULong64)
+
+    scalar_float_types = (CmdArgType.DevFloat, CmdArgType.DevDouble,)
+
+    scalar_numerical_types = scalar_int_types + scalar_long_types + scalar_float_types
+
+    scalar_str_types = (CmdArgType.DevString, CmdArgType.ConstDevString,)
+
+    scalar_types = scalar_numerical_types + scalar_str_types + \
+        (CmdArgType.DevBoolean, CmdArgType.DevEncoded,
+         CmdArgType.DevUChar, CmdArgType.DevVoid)
+
+    def __init__(self):
+        self.db = None
+        if Util._UseDb:
+            self.db = Database()
+
+    def set_default_property_values(self, dev_class, class_prop, dev_prop):
+        """
+            set_default_property_values(self, dev_class, class_prop, dev_prop) -> None
+
+                Sets the default property values
+
+            Parameters :
+                - dev_class : (DeviceClass) device class object
+                - class_prop : (dict<str,>) class properties
+                - dev_prop : (dict<str,>) device properties
+
+            Return     : None
+        """
+        for name in class_prop.keys():
+            type = self.get_property_type(name, class_prop)
+            val  = self.get_property_values(name, class_prop)
+            val  = self.values2string(val, type)
+            desc = self.get_property_description(name, class_prop)
+            dev_class.add_wiz_class_prop(name, desc, val)
+
+        for name in dev_prop.keys():
+            type = self.get_property_type(name, dev_prop)
+            val  = self.get_property_values(name, dev_prop)
+            val  = self.values2string(val, type)
+            desc = self.get_property_description(name, dev_prop)
+            dev_class.add_wiz_dev_prop(name, desc, val)
+
+    def get_class_properties(self, dev_class, class_prop):
+        """
+            get_class_properties(self, dev_class, class_prop) -> None
+
+                    Returns the class properties
+
+                Parameters :
+                    - dev_class : (DeviceClass) the DeviceClass object
+                    - class_prop : [in, out] (dict<str, None>) the property names. Will be filled
+                                   with property values
+
+                Return     : None"""
+        # initialize default values
+        if class_prop == {} or Util._UseDb == False:
+            return
+
+        # call database to get properties
+        props = self.db.get_class_property(dev_class.get_name(), class_prop.keys())
+
+        # if value defined in database, store it
+        for name in class_prop.keys():
+            if props[name]:
+                type   = self.get_property_type(name, class_prop)
+                values = self.stringArray2values(props[name], type)
+                self.set_property_values(name, class_prop, values)
+            else:
+                print name, " property NOT found in database"
+
+    def get_device_properties(self, dev, class_prop, dev_prop):
+        """
+            get_device_properties(self, dev, class_prop, dev_prop) -> None
+
+                    Returns the device properties
+
+                Parameters :
+                    - dev : (DeviceImpl) the device object
+                    - class_prop : (dict<str, obj>) the class properties
+                    - dev_prop : [in,out] (dict<str, None>) the device property names
+
+                Return     : None"""
+        #    initialize default properties
+        if dev_prop == {} or Util._UseDb == False:
+            return
+
+        #    Call database to get properties
+        props = self.db.get_device_property(dev.get_name(),dev_prop.keys())
+        #    if value defined in database, store it
+        for name in dev_prop.keys():
+            prop_value = props[name]
+            if len(prop_value):
+                data_type = self.get_property_type(name, dev_prop)
+                values = self.stringArray2values(prop_value, data_type)
+                if not self.is_empty_seq(values):
+                    self.set_property_values(name, dev_prop, values)
+                else:
+                    #    Try to get it from class property
+                    values = self.get_property_values(name, class_prop)
+                    if not self.is_empty_seq(values):
+                        if not self.is_seq(values):
+                            values = [values]
+                        data_type = self.get_property_type(name, class_prop)
+                        values = self.stringArray2values(values, data_type)
+                        if not self.is_empty_seq(values):
+                            self.set_property_values(name, dev_prop, values)
+            else:
+                    #    Try to get it from class property
+                values = self.get_property_values(name, class_prop)
+                if not self.is_empty_seq(values):
+                    if not self.is_seq(values):
+                        values = [values]
+                    data_type = self.get_property_type(name, class_prop)
+                    values = self.stringArray2values(values, data_type)
+                    if not self.is_empty_seq(values):
+                        self.set_property_values(name, dev_prop, values)
+
+    def is_seq(self, v):
+        """
+            is_seq(self, v) -> bool
+
+                    Helper method. Determines if the object is a sequence
+
+                Parameters :
+                    - v : (object) the object to be analysed
+
+                Return     : (bool) True if the object is a sequence or False otherwise"""
+        return operator.isSequenceType(v)
+
+    def is_empty_seq(self, v):
+        """
+            is_empty_seq(self, v) -> bool
+
+                    Helper method. Determines if the object is an empty sequence
+
+                Parameters :
+                    - v : (object) the object to be analysed
+
+                Return     : (bool) True if the object is a sequence which is empty or False otherwise"""
+        return self.is_seq(v) and not len(v)
+
+    def get_property_type(self, prop_name, properties):
+        """
+            get_property_type(self, prop_name, properties) -> CmdArgType
+
+                    Gets the property type for the given property name using the
+                    information given in properties
+
+                Parameters :
+                    - prop_name : (str) property name
+                    - properties : (dict<str,data>) property data
+
+                Return     : (CmdArgType) the tango type for the given property"""
+        try:
+            tg_type = properties[prop_name][0]
+        except:
+            tg_type = CmdArgType.DevVoid
+        return tg_type
+
+    def set_property_values(self, prop_name, properties, values):
+        """
+            set_property_values(self, prop_name, properties, values) -> None
+
+                    Sets the property value in the properties
+
+                Parameters :
+                    - prop_name : (str) property name
+                    - properties : (dict<str,obj>) [in,out] dict which will contain the value
+                    - values : (seq) the new property value
+
+                Return     : None"""
+
+        properties[prop_name][2] = values
+
+    def get_property_values(self, prop_name, properties):
+        """
+            get_property_values(self, prop_name, properties) -> obj
+
+                    Gets the property value
+
+                Parameters :
+                    - prop_name : (str) property name
+                    - properties : (dict<str,obj>) properties
+                Return     : (obj) the value for the given property name"""
+        try:
+            tg_type = self.get_property_type(prop_name, properties)
+            val  = properties[prop_name][2]
+        except:
+            val = []
+
+        if is_array(tg_type) or (operator.isSequenceType(val) and not len(val)):
+            return val
+        else:
+            if operator.isSequenceType(val) and not type(val) in types.StringTypes:
+                return val[0]
+            else:
+                return val
+
+    def get_property_description(self, prop_name, properties):
+        """
+            get_property_description(self, prop_name, properties) -> obj
+
+                    Gets the property description
+
+                Parameters :
+                    - prop_name : (str) property name
+                    - properties : (dict<str,obj>) properties
+                Return     : (str) the description for the given property name"""
+        return properties[prop_name][1]
+
+    def stringArray2values(self, argin, argout_type):
+        """internal helper method"""
+        return seqStr_2_obj(argin, argout_type)
+
+    def values2string(self, argin, argout_type):
+        """internal helper method"""
+        return obj_2_str(argin, argout_type)
+
+class DeviceClass(_DeviceClass):
+    """Base class for all TANGO device-class class.
+       A TANGO device-class class is a class where is stored all
+       data/method common to all devices of a TANGO device class"""
+
+    class_property_list = {}
+    device_property_list = {}
+    cmd_list = {}
+    attr_list = {}
+
+    def __init__(self, name):
+        _DeviceClass.__init__(self,name)
+        self.dyn_att_added_methods = []
+        try:
+            self.prop_util = PropUtil()
+            self.py_dev_list = []
+            has_cl_prop = hasattr(self,"class_property_list")
+            has_dev_prop = hasattr(self,"device_property_list")
+            if has_cl_prop and has_dev_prop:
+                self.prop_util.set_default_property_values(self,self.class_property_list, self.device_property_list)
+                self.prop_util.get_class_properties(self, self.class_property_list)
+                for prop_name in self.class_property_list.keys():
+                    setattr(self, prop_name, self.prop_util.get_property_values(prop_name, self.class_property_list))
+        except DevFailed, e:
+            print "----> ", e
+    
+    def __str__(self):
+        return '%s(%s)' % (self.__class__.__name__, self.get_name())
+    
+    def __repr__(self):
+        return '%s(%s)' % (self.__class__.__name__, self.get_name())    
+    
+    def __throw_create_attribute_exception(self, msg):
+        """Helper method to throw DevFailed exception when inside create_attribute"""
+        Except.throw_exception("PyDs_WrongAttributeDefinition", msg, "create_attribute()")
+
+    def __throw_create_command_exception(self, msg):
+        """Helper method to throw DevFailed exception when inside create_command"""
+        Except.throw_exception("PyDs_WrongCommandDefinition", msg, "create_command()")
+
+    def __attribute_factory(self, attr_list):
+        """for internal usage only"""
+
+        for attr_name, attr_info in self.attr_list.iteritems():
+            self.__create_attribute(attr_list, attr_name, attr_info)
+
+    def __create_attribute(self, attr_list, attr_name, attr_info):
+        """for internal usage only"""
+        name = self.get_name()
+
+        # check for well defined attribute info
+
+        # check parameter
+        if not operator.isSequenceType(attr_info):
+            msg = "Wrong data type for value for describing attribute %s in " \
+                  "class %s\nMust be a sequence with 1 or 2 elements" % (attr_name, name)
+            self.__throw_create_attribute_exception(msg)
+
+        if len(attr_info) < 1 or len(attr_info) > 2:
+            msg = "Wrong number of argument for describing attribute %s in " \
+                  "class %s\nMust be a sequence with 1 or 2 elements" % (attr_name, name)
+            self.__throw_create_attribute_exception(msg)
+
+        extra_info = {}
+        if len(attr_info) == 2:
+            # attr_info[1] must be a dictionary
+            # extra_info = attr_info[1], with all the keys lowercase
+            for k, v in attr_info[1].iteritems():
+                extra_info[k.lower()] = v
+
+        attr_info = attr_info[0]
+
+        attr_info_len = len(attr_info)
+        # check parameter
+        if not operator.isSequenceType(attr_info) or attr_info_len < 3 or attr_info_len > 5:
+            msg = "Wrong data type for describing mandatory information for attribute %s " \
+                  "in class %s\nMust be a sequence with 3, 4 or 5 elements" % (attr_name, name)
+            self.__throw_create_attribute_exception(msg)
+
+        # get data type
+        attr_type = CmdArgType.DevVoid
+        try:
+            attr_type = CmdArgType(attr_info[0])
+        except:
+            msg = "Wrong data type in attribute argument for attribute %s in " \
+                  "class %s\nAttribute data type (first element in first " \
+                  "sequence) must be a PyTango.CmdArgType"
+            self.__throw_create_attribute_exception(msg)
+
+        # get format
+        attr_format = AttrDataFormat.SCALAR
+        try:
+            attr_format = AttrDataFormat(attr_info[1])
+        except:
+            msg = "Wrong data format in attribute argument for attribute %s in " \
+                  "class %s\nAttribute data format (second element in first " \
+                  "sequence) must be a PyTango.AttrDataFormat"
+            self.__throw_create_attribute_exception(msg)
+
+        dim_x, dim_y = 1, 0
+        if attr_format == AttrDataFormat.SCALAR:
+            if attr_info_len != 3:
+                msg = "Wrong data type in attribute argument for attribute %s in " \
+                      "class %s\nSequence describing mandatory attribute parameters " \
+                      "for scalar attribute must have 3 elements"
+                self.__throw_create_attribute_exception(msg)
+        elif attr_format == AttrDataFormat.SPECTRUM:
+            if attr_info_len != 4:
+                msg = "Wrong data type in attribute argument for attribute %s in " \
+                      "class %s\nSequence describing mandatory attribute parameters " \
+                      "for spectrum attribute must have 4 elements"
+                self.__throw_create_attribute_exception(msg)
+            try:
+                dim_x = int(attr_info[3])
+            except:
+                msg = "Wrong data type in attribute argument for attribute %s in " \
+                      "class %s\n4th element in sequence describing mandatory dim_x " \
+                      "attribute parameter for spectrum attribute must be an integer"
+                self.__throw_create_attribute_exception(msg)
+        elif attr_format == AttrDataFormat.IMAGE:
+            if attr_info_len != 5:
+                msg = "Wrong data type in attribute argument for attribute %s in " \
+                      "class %s\nSequence describing mandatory attribute parameters " \
+                      "for image attribute must have 5 elements"
+                self.__throw_create_attribute_exception(msg)
+            try:
+                dim_x = int(attr_info[3])
+            except:
+                msg = "Wrong data type in attribute argument for attribute %s in " \
+                      "class %s\n4th element in sequence describing mandatory dim_x " \
+                      "attribute parameter for image attribute must be an integer"
+                self.__throw_create_attribute_exception(msg)
+            try:
+                dim_y = int(attr_info[4])
+            except:
+                msg = "Wrong data type in attribute argument for attribute %s in " \
+                      "class %s\n5th element in sequence describing mandatory dim_y " \
+                      "attribute parameter for image attribute must be an integer"
+                self.__throw_create_attribute_exception(msg)
+
+        #get write type
+        attr_write = AttrWriteType.READ
+        try:
+            attr_write = AttrWriteType(attr_info[2])
+        except:
+            msg = "Wrong data write type in attribute argument for attribute %s in " \
+                  "class %s\nAttribute write type (third element in first " \
+                  "sequence) must be a PyTango.AttrWriteType"
+            self.__throw_create_attribute_exception(msg)
+
+        # check that the method(s) to be executed exists
+        read_method_name = "read_%s" % attr_name
+        write_method_name = "write_%s" % attr_name
+        is_allowed_name = "is_%s_allowed" % attr_name
+
+        try:
+            display_level = DispLevel(extra_info.get("display level", DispLevel.OPERATOR))
+        except:
+            msg = "Wrong display level in attribute information for attribute %s in " \
+                  "class %s\nAttribute information for display level is not a " \
+                  "PyTango.DispLevel" % (attr_name, name)
+            self.__throw_create_attribute_exception(msg)
+
+        try:
+            polling_period = int(extra_info.get("polling period", -1))
+        except:
+            msg = "Wrong polling period in attribute information for attribute %s in " \
+                  "class %s\nAttribute information for polling period is not an " \
+                  "integer" % (attr_name, name)
+            self.__throw_create_attribute_exception(msg)
+
+        memorized, hw_memorized = extra_info.get("memorized", "false"), False
+        if memorized == "true":
+            memorized, hw_memorized = True, True
+        elif memorized == "true_without_hard_applied":
+            memorized = True
+        else:
+            memorized = False
+
+        att_prop = self.__create_user_default_attr_prop(attr_name, extra_info)
+
+        self._create_attribute(attr_list, attr_name, attr_type, attr_format,
+                               attr_write, dim_x, dim_y,
+                               display_level, polling_period,
+                               memorized, hw_memorized,
+                               read_method_name, write_method_name,
+                               is_allowed_name,
+                               att_prop)
+
+    def __create_user_default_attr_prop(self, attr_name, extra_info):
+        """for internal usage only"""
+        p = UserDefaultAttrProp()
+        for k, v in extra_info.iteritems():
+            k_lower = k.lower()
+            method_name = "set_%s" % k_lower.replace(' ','_')
+            if hasattr(p, method_name):
+                method = getattr(p, method_name)
+                method(str(v))
+            elif k == 'delta_time':
+                p.set_delta_t(str(v))
+            elif not k_lower in ('display level', 'polling period', 'memorized'):
+                name = self.get_name()
+                msg = "Wrong definition of attribute %s in " \
+                      "class %s\nThe object extra information '%s' " \
+                      "is not recognized!" % (attr_name, name, k)
+                self.__throw_create_attribute_exception(msg)
+        return p
+
+    def __command_factory(self):
+        """for internal usage only"""
+        name = self.get_name()
+        class_info = get_class(name)
+        deviceimpl_class = class_info[1]
+
+        if not hasattr(deviceimpl_class, "init_device"):
+            msg = "Wrong definition of class %s\n" \
+                  "The init_device() method does not exist!" % name
+            Except.throw_exception("PyDs_WrongCommandDefinition", msg, "command_factory()")
+
+        for cmd_name, cmd_info in self.cmd_list.iteritems():
+            self.__create_command(deviceimpl_class, cmd_name, cmd_info)
+
+    def __create_command(self, deviceimpl_class, cmd_name, cmd_info):
+        """for internal usage only"""
+        name = self.get_name()
+
+        # check for well defined command info
+
+        # check parameter
+        if not operator.isSequenceType(cmd_info):
+            msg = "Wrong data type for value for describing command %s in " \
+                  "class %s\nMust be a sequence with 2 or 3 elements" % (cmd_name, name)
+            self.__throw_create_command_exception(msg)
+
+        if len(cmd_info) < 2 or len(cmd_info) > 3:
+            msg = "Wrong number of argument for describing command %s in " \
+                  "class %s\nMust be a sequence with 2 or 3 elements" % (cmd_name, name)
+            self.__throw_create_command_exception(msg)
+
+        param_info, result_info = cmd_info[0], cmd_info[1]
+
+        if not operator.isSequenceType(param_info):
+            msg = "Wrong data type in command argument for command %s in " \
+                  "class %s\nCommand parameter (first element) must be a sequence" % (cmd_name, name)
+            self.__throw_create_command_exception(msg)
+
+        if len(param_info) < 1 or len(param_info) > 2:
+            msg = "Wrong data type in command argument for command %s in " \
+                  "class %s\nSequence describing command parameters must contain " \
+                  "1 or 2 elements"
+            self.__throw_create_command_exception(msg)
+
+        param_type = CmdArgType.DevVoid
+        try:
+            param_type = CmdArgType(param_info[0])
+        except:
+            msg = "Wrong data type in command argument for command %s in " \
+                  "class %s\nCommand parameter type (first element in first " \
+                  "sequence) must be a PyTango.CmdArgType"
+            self.__throw_create_command_exception(msg)
+
+        param_desc = ""
+        if len(param_info) > 1:
+            param_desc = param_info[1]
+            if not type(param_desc) in types.StringTypes:
+                msg = "Wrong data type in command parameter for command %s in " \
+                      "class %s\nCommand parameter description (second element " \
+                      "in first sequence), when given, must be a string"
+                self.__throw_create_command_exception(msg)
+
+        # Check result
+        if not operator.isSequenceType(result_info):
+            msg = "Wrong data type in command result for command %s in " \
+                  "class %s\nCommand result (second element) must be a sequence" % (cmd_name, name)
+            self.__throw_create_command_exception(msg)
+
+        if len(result_info) < 1 or len(result_info) > 2:
+            msg = "Wrong data type in command result for command %s in " \
+                  "class %s\nSequence describing command result must contain " \
+                  "1 or 2 elements" % (cmd_name, name)
+            self.__throw_create_command_exception(msg)
+
+        result_type = CmdArgType.DevVoid
+        try:
+            result_type = CmdArgType(result_info[0])
+        except:
+            msg = "Wrong data type in command result for command %s in " \
+                  "class %s\nCommand result type (first element in second " \
+                  "sequence) must be a PyTango.CmdArgType" % (cmd_name, name)
+            self.__throw_create_command_exception(msg)
+
+        result_desc = ""
+        if len(result_info) > 1:
+            result_desc = result_info[1]
+            if not type(result_desc) in types.StringTypes:
+                msg = "Wrong data type in command result for command %s in " \
+                      "class %s\nCommand parameter description (second element " \
+                      "in second sequence), when given, must be a string" % (cmd_name, name)
+                self.__throw_create_command_exception(msg)
+
+        # If it is defined, get addictional dictionnary used for optional parameters
+        display_level, default_command, polling_period = DispLevel.OPERATOR, False, -1
+
+        if len(cmd_info) == 3:
+            extra_info = cmd_info[2]
+            if not operator.isMappingType(extra_info):
+                msg = "Wrong data type in command information for command %s in " \
+                      "class %s\nCommand information (third element in sequence), " \
+                      "when given, must be a dictionary" % (cmd_name, name)
+                self.__throw_create_command_exception(msg)
+
+            if len(extra_info) > 3:
+                msg = "Wrong data type in command information for command %s in " \
+                      "class %s\nThe optional dictionary can not have more than " \
+                      "three elements" % (cmd_name, name)
+                self.__throw_create_command_exception(msg)
+
+            for info_name, info_value in extra_info.iteritems():
+                info_name_lower = info_name.lower()
+                if info_name_lower == "display level":
+                    try:
+                        display_level = DispLevel(info_value)
+                    except:
+                        msg = "Wrong data type in command information for command %s in " \
+                              "class %s\nCommand information for display level is not a " \
+                              "PyTango.DispLevel" % (cmd_name, name)
+                        self.__throw_create_command_exception(msg)
+                elif info_name_lower == "default command":
+                    if not type(info_value) in types.StringTypes:
+                        msg = "Wrong data type in command information for command %s in " \
+                              "class %s\nCommand information for default command is not a " \
+                              "string" % (cmd_name, name)
+                        self.__throw_create_command_exception(msg)
+                    v = info_value.lower()
+                    default_command = v == 'true'
+                elif info_name_lower == "polling period":
+                    try:
+                        polling_period = int(info_value)
+                    except:
+                        msg = "Wrong data type in command information for command %s in " \
+                              "class %s\nCommand information for polling period is not an " \
+                              "integer" % (cmd_name, name)
+                        self.__throw_create_command_exception(msg)
+                else:
+                    msg = "Wrong data type in command information for command %s in " \
+                          "class %s\nCommand information has unknown key " \
+                          "%s" % (cmd_name, name, info_name)
+                    self.__throw_create_command_exception(msg)
+
+        # check that the method to be executed exists
+        try:
+            cmd = getattr(deviceimpl_class, cmd_name)
+            if not callable(cmd):
+                msg = "Wrong definition of command %s in " \
+                      "class %s\nThe object exists in class but is not " \
+                      "a method!" % (cmd_name, name)
+                self.__throw_create_command_exception(msg)
+        except AttributeError:
+            msg = "Wrong definition of command %s in " \
+                  "class %s\nThe command method does not exist!" % (cmd_name, name)
+            self.__throw_create_command_exception(msg)
+
+        is_allowed_name = "is_%s_allowed" % cmd_name
+        try:
+            is_allowed = getattr(deviceimpl_class, is_allowed_name)
+            if not callable(is_allowed):
+                msg = "Wrong definition of command %s in " \
+                      "class %s\nThe object '%s' exists in class but is " \
+                      "not a method!" % (cmd_name, name, is_allowed_name)
+                self.__throw_create_command_exception(msg)
+        except:
+            is_allowed_name = ""
+
+        self._create_command(cmd_name, param_type, result_type,
+                             param_desc, result_desc,
+                             display_level, default_command,
+                             polling_period, is_allowed_name)
+
+    def device_factory(self, device_list):
+        """for internal usage only"""
+       
+        klass = self.__class__
+        klass_name = klass.__name__
+        info, klass = get_class_by_class(klass), get_constructed_class_by_class(klass)
+        
+        if info is None:
+            raise RuntimeError("Device class '%s' is not registered" % klass_name)
+
+        if klass is None:
+            print get_constructed_classes()
+            raise RuntimeError("Device class '%s' as not been constructed" % klass_name)
+        
+        deviceClassClass, deviceImplClass, deviceImplName = info
+        deviceImplClass._device_class_instance = klass
+
+        tmp_dev_list = []
+        for dev_name in device_list:
+            device = deviceImplClass(klass, dev_name)
+            self.cpp_add_device(device)
+            tmp_dev_list.append(device)
+
+        self.dyn_attr(tmp_dev_list)
+
+        for dev in tmp_dev_list:
+            if Util._UseDb and not Util._FileDb:
+                self.export_device(dev)
+            else:
+                self.export_device(dev, dev.get_name())
+        self.py_dev_list += tmp_dev_list
+
+    def create_device(self, device_name, alias=None, cb=None):
+        """
+            create_device(self, device_name, alias=None, cb=None) -> None
+            
+                Creates a new device of the given class in the database, creates a new
+                DeviceImpl for it and calls init_device (just like it is done for
+                existing devices when the DS starts up)
+        
+                An optional parameter callback is called AFTER the device is 
+                registered in the database and BEFORE the init_device for the
+                newly created device is called
+                
+            Throws PyTango.DevFailed:
+                - the device name exists already or
+                - the given class is not registered for this DS.
+                - the cb is not a callable
+                
+            New in PyTango 7.1.2
+            
+            Parameters :
+                - device_name : (str) the device name
+                - alias : (str) optional alias. Default value is None meaning do not create device alias
+                - cb : (callable) a callback that is called AFTER the device is registered
+                       in the database and BEFORE the init_device for the newly created
+                       device is called. Typically you may want to put device and/or attribute
+                       properties in the database here. The callback must receive a parameter:
+                       device name (str). Default value is None meaning no callback
+            
+            Return     : None"""
+        util = Util.instance()
+        util.create_device(self.get_name(), device_name, alias=alias, cb=cb)
+
+    def delete_device(self, device_name):
+        """
+            delete_device(self, klass_name, device_name) -> None
+            
+                Deletes an existing device from the database and from this running
+                server
+        
+                Throws PyTango.DevFailed:
+                    - the device name doesn't exist in the database
+                    - the device name doesn't exist in this DS.
+            
+            New in PyTango 7.1.2
+            
+            Parameters :
+                - klass_name : (str) the device class name
+                - device_name : (str) the device name
+            
+            Return     : None"""
+        util = Util.instance()
+        util.delete_device(self.get_name(), device_name)
+        
+    def dyn_attr(self,device_list):
+        """
+            dyn_attr(self,device_list) -> None
+
+                Default implementation does not do anything
+                Overwrite in order to provide dynamic attributes
+
+            Parameters :
+                - device_list : (seq<DeviceImpl>) sequence of devices of this class
+
+            Return     : None"""
+        pass
+
+    def device_destroyer(self,name):
+        """for internal usage only"""
+        name = name.lower()
+        for d in self.py_dev_list:
+            dname = d.get_name().lower()
+            if dname == name:
+                dev_cl = d.get_device_class()
+                # the internal C++ device_destroyer isn't case sensitive so we
+                # use the internal DeviceImpl name to make sure the DeviceClass
+                # finds it
+                dev_cl._device_destroyer(d.get_name())
+                self.py_dev_list.remove(d)
+                return
+        err_mess = "Device " + name + " not in Tango class device list!"
+        Except.throw_exception("PyAPI_CantDestroyDevice",err_mess,"DeviceClass.device_destroyer")
+
+def __init_DeviceClass():
+    pass
+
+def __doc_DeviceClass():
+    def document_method(method_name, desc, append=True):
+        return __document_method(DeviceClass, method_name, desc, append)
+
+    document_method("export_device", """
+    export_device(self, dev, corba_dev_name = 'Unused') -> None
+
+            For internal usage only
+
+        Parameters :
+            - dev : (DeviceImpl) device object
+            - corba_dev_name : (str) CORBA device name. Default value is 'Unused'
+
+        Return     : None
+    """ )
+
+    document_method("register_signal", """
+    register_signal(self, signo) -> None
+
+            Register a signal.
+            Register this class as class to be informed when signal signo
+            is sent to to the device server process
+
+        Parameters :
+            - signo : (int) signal identifier
+
+        Return     : None
+    """ )
+
+    document_method("unregister_signal", """
+    unregister_signal(self, signo) -> None
+
+            Unregister a signal.
+            Unregister this class as class to be informed when signal signo
+            is sent to to the device server process
+
+        Parameters :
+            - signo : (int) signal identifier
+        Return     : None
+    """ )
+
+    document_method("signal_handler", """
+    signal_handler(self, signo) -> None
+
+            Signal handler.
+
+            The method executed when the signal arrived in the device server process.
+            This method is defined as virtual and then, can be redefined following
+            device class needs.
+
+        Parameters :
+            - signo : (int) signal identifier
+        Return     : None
+    """ )
+
+    document_method("get_name", """
+    get_name(self) -> str
+
+            Get the TANGO device class name.
+
+        Parameters : None
+        Return     : (str) the TANGO device class name.
+    """ )
+
+    document_method("get_type", """
+    get_type(self) -> str
+
+            Gets the TANGO device type name.
+
+        Parameters : None
+        Return     : (str) the TANGO device type name
+    """ )
+
+    document_method("get_doc_url", """
+    get_doc_url(self) -> str
+
+            Get the TANGO device class documentation URL.
+
+        Parameters : None
+        Return     : (str) the TANGO device type name
+    """ )
+
+    document_method("set_type", """
+    set_type(self, dev_type) -> None
+
+            Set the TANGO device type name.
+
+        Parameters :
+            - dev_type : (str) the new TANGO device type name
+        Return     : None
+    """ )
+
+    document_method("get_cvs_tag", """
+    get_cvs_tag(self) -> str
+
+            Gets the cvs tag
+
+        Parameters : None
+        Return     : (str) cvs tag
+    """ )
+
+    document_method("get_cvs_location", """
+    get_cvs_location(self) -> None
+
+            Gets the cvs localtion
+
+        Parameters : None
+        Return     : (str) cvs location
+    """ )
+
+    document_method("get_device_list", """
+    get_device_list(self) -> sequence<PyTango.DeviceImpl>
+
+            Gets the list of PyTango.DeviceImpl objects for this class
+
+        Parameters : None
+        Return     : (sequence<PyTango.DeviceImpl>) list of PyTango.DeviceImpl objects for this class
+    """ )
+    
+    document_method("add_wiz_dev_prop", """
+    add_wiz_dev_prop(self, str, str) -> None
+    add_wiz_dev_prop(self, str, str, str) -> None
+
+            For internal usage only
+
+        Parameters : None
+        Return     : None
+    """ )
+
+    document_method("add_wiz_class_prop", """
+    add_wiz_class_prop(self, str, str) -> None
+    add_wiz_class_prop(self, str, str, str) -> None
+
+            For internal usage only
+
+        Parameters : None
+        Return     : None
+    """ )
+
+def init(doc=True):
+    __init_DeviceClass()
+    if doc:
+        __doc_DeviceClass()
diff --git a/PyTango/device_data.py b/PyTango/device_data.py
new file mode 100644
index 0000000..e47c4a7
--- /dev/null
+++ b/PyTango/device_data.py
@@ -0,0 +1,94 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = []
+            
+__docformat__ = "restructuredtext"
+
+from utils import document_method as __document_method
+from _PyTango import DeviceData
+
+def __DeviceData__get_data(self):
+    return self.get_data_raw().extract()
+
+def __init_DeviceData():
+    pass
+
+def __doc_DeviceData():
+    def document_method(method_name, desc, append=True):
+        return __document_method(DeviceData, method_name, desc, append)
+
+    DeviceData.__doc__ = """
+        This is the fundamental type for sending and receiving data from
+        device commands. The values can be inserted and extracted using the
+        insert() and extract() methods.
+    """
+
+    document_method("extract", """
+    extract(self) -> any
+
+            Get the actual value stored in the DeviceData.
+
+        Parameters : None
+        Return     : Whatever is stored there, or None.
+    """ )
+
+    document_method("insert", """
+    insert(self, data_type, value) -> None
+
+            Inserts a value in the DeviceData.
+
+        Parameters :
+                - data_type : 
+                - value     : (any) The value to insert
+        Return     : Whatever is stored there, or None.
+    """ )
+
+    document_method("is_empty", """
+    is_empty(self) -> bool
+
+            It can be used to test whether the DeviceData object has been
+            initialized or not.
+
+        Parameters : None
+        Return     : True or False depending on whether the DeviceData object
+                    contains data or not.
+    """ )
+
+    document_method("get_type", """
+    get_type(self) -> CmdArgType
+
+            This method returns the Tango data type of the data inside the
+            DeviceData object.
+
+        Parameters : None
+        Return     : The content arg type.
+    """ )
+
+def init(doc=True):
+    __init_DeviceData()
+    if doc:
+        __doc_DeviceData()
+
diff --git a/PyTango/device_proxy.py b/PyTango/device_proxy.py
new file mode 100644
index 0000000..346bc57
--- /dev/null
+++ b/PyTango/device_proxy.py
@@ -0,0 +1,1692 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = []
+            
+__docformat__ = "restructuredtext"
+
+import operator, types
+
+from _PyTango import StdStringVector
+from _PyTango import DbData, DbDatum
+from _PyTango import AttributeInfo, AttributeInfoEx
+from _PyTango import AttributeInfoList, AttributeInfoListEx
+from _PyTango import DeviceProxy, DeviceAttribute, DeviceData
+from _PyTango import __CallBackAutoDie, __CallBackPushEvent, EventType
+from _PyTango import DevFailed
+from _PyTango import ExtractAs
+from PyTango.utils import seq_2_StdStringVector, StdStringVector_2_seq
+from PyTango.utils import seq_2_DbData, DbData_2_dict
+from utils import document_method as __document_method
+
+#-------------------------------------------------------------------------------
+# Pythonic API: transform tango commands into methods and tango attributes into
+# class members
+#-------------------------------------------------------------------------------
+
+def __check_read_attribute(dev_attr):
+    if dev_attr.has_failed:
+        raise DevFailed(*dev_attr.get_err_stack())
+    return dev_attr
+
+def __DeviceProxy__refresh_cmd_cache(self):
+    self.__cmd_cache = [cmd.cmd_name.lower() for cmd in self.command_list_query()]
+
+def __DeviceProxy__refresh_attr_cache(self):
+    attr_cache = [attr_name.lower() for attr_name in self.get_attribute_list()]
+    self.__dict__['__attr_cache'] = attr_cache
+
+def __DeviceProxy__getattr(self, name):
+    # trait_names is a feature of IPython. Hopefully they will solve
+    # ticket http://ipython.scipy.org/ipython/ipython/ticket/229 someday
+    # and the ugly trait_names could be removed.
+    if name[:2] == "__" or name == 'trait_names':
+        raise AttributeError, name
+    
+    find_cmd = True
+    if not hasattr(self, '__cmd_cache') or name.lower() not in self.__cmd_cache:
+        try:
+            self.__refresh_cmd_cache()
+        except:
+            find_cmd = False
+    
+    if find_cmd and name.lower() in self.__cmd_cache:
+        def f(*args,**kwds): return self.command_inout(name, *args, **kwds)
+        return f
+    
+    find_attr = True
+    if not hasattr(self, '__attr_cache') or name.lower() not in self.__attr_cache:
+        try:
+            self.__refresh_attr_cache()
+        except:
+            find_attr = False
+    
+    if not find_attr or name.lower() not in self.__attr_cache:
+        raise AttributeError, name
+    
+    return self.read_attribute(name).value
+
+def __DeviceProxy__setattr(self, name, value):
+    try:
+        if not hasattr(self, '__attr_cache') or name.lower() not in self.__attr_cache:
+            self.__refresh_attr_cache()
+    except:
+        self.__dict__[name] = value
+        return
+        
+    if name.lower() in self.__attr_cache:
+        self.write_attribute(name, value)
+    else:
+        self.__dict__[name] = value
+
+
+def __DeviceProxy__getAttributeNames(self):
+    """Return list of magic attributes to extend introspection."""
+    try:
+        lst = [cmd.cmd_name for cmd in self.command_list_query()]
+        lst += self.get_attribute_list()
+        lst += map(str.lower, lst)
+        lst.sort()
+        return lst
+    except Exception:
+        pass
+    return []
+
+def __DeviceProxy__del(self):
+    self.__unsubscribe_event_all()
+
+def __DeviceProxy__getitem(self, key):
+    return self.read_attribute(key)
+
+def __DeviceProxy__setitem(self, key, value):
+    return self.write_attribute(key, value)
+
+def __DeviceProxy__contains(self, key):
+    return key.lower() in map(str.lower, self.get_attribute_list())
+
+def __DeviceProxy__read_attribute(self, value, extract_as=ExtractAs.Numpy):
+    return __check_read_attribute(self._read_attribute(value, extract_as))
+
+def __DeviceProxy__read_attributes_asynch(self, attr_names, cb=None, extract_as=ExtractAs.Numpy):
+    """
+    read_attributes_asynch( self, attr_names) -> int
+
+            Read asynchronously (polling model) the list of specified attributes.
+
+        Parameters :
+                - attr_names : (sequence<str>) A list of attributes to read.
+                            It should be a StdStringVector or a sequence of str.
+        Return     : an asynchronous call identifier which is needed to get
+                        attributes value.
+
+        Throws     : ConnectionFailed
+
+        New in PyTango 7.0.0
+
+    read_attributes_asynch( self, attr_names, callback, extract_as=Numpy) -> None
+
+            Read asynchronously (callback model) an attribute list.
+
+        Parameters :
+                - attr_names : (sequence<str>) A list of attributes to read. See read_attributes.
+                - callback   : (callable) This callback object should be an instance of a
+                            user class with an attr_read() method. It can also
+                            be any callable object.
+                - extract_as : (ExtractAs) Defaults to numpy.
+        Return     : None
+
+        Throws     : ConnectionFailed
+
+        New in PyTango 7.0.0
+    """
+    if cb is None:
+        return self.__read_attributes_asynch(attr_names)
+
+    cb2 = __CallBackAutoDie()
+    if callable(cb):
+        cb2.attr_read = cb
+    else:
+        cb2.attr_read = cb.attr_read
+    return self.__read_attributes_asynch(attr_names, cb2, extract_as)
+
+def __DeviceProxy__read_attribute_asynch(self, attr_name, cb=None):
+    """
+    read_attribute_asynch( self, attr_name) -> int
+    read_attribute_asynch( self, attr_name, callback) -> None
+
+            Shortcut to self.read_attributes_asynch([attr_name], cb)
+
+        New in PyTango 7.0.0
+    """
+    return self.read_attributes_asynch([attr_name], cb)
+
+def __DeviceProxy__read_attribute_reply(self, *args, **kwds):
+    """
+    read_attribute_reply( self, id, extract_as) -> int
+    read_attribute_reply( self, id, timeout, extract_as) -> None
+
+            Shortcut to self.read_attributes_reply()[0]
+            
+        New in PyTango 7.0.0
+    """
+    return __check_read_attribute(self.read_attributes_reply(*args, **kwds)[0])
+
+def __DeviceProxy__write_attributes_asynch(self, attr_values, cb=None):
+    """
+    write_attributes_asynch( self, values) -> int
+    
+            Write asynchronously (polling model) the specified attributes.
+            
+        Parameters :
+                - values : (any) See write_attributes.
+        Return     : An asynchronous call identifier which is needed to get the
+                    server reply
+
+        Throws     : ConnectionFailed
+        
+        New in PyTango 7.0.0
+
+    write_attributes_asynch( self, values, callback) -> None
+    
+            Write asynchronously (callback model) a single attribute.
+        
+        Parameters :
+                - values   : (any) See write_attributes.
+                - callback : (callable) This callback object should be an instance of a user
+                            class with an attr_written() method . It can also be any
+                            callable object.
+        Return     : None
+
+        Throws     : ConnectionFailed
+        
+        New in PyTango 7.0.0
+    """
+    if cb is None:
+        return self.__write_attributes_asynch(attr_values)
+
+    cb2 = __CallBackAutoDie()
+    if callable(cb):
+        cb2.attr_write = cb
+    else:
+        cb2.attr_write = cb.attr_write
+    return self.__write_attributes_asynch(attr_values, cb2)
+
+def __DeviceProxy__write_attribute_asynch(self, attr_name, value, cb=None):
+    """
+    write_attributes_asynch( self, values) -> int
+    write_attributes_asynch( self, values, callback) -> None
+
+            Shortcut to self.write_attributes_asynch([attr_name, value], cb)
+
+        New in PyTango 7.0.0
+    """
+    return self.write_attributes_asynch([(attr_name, value)], cb)
+
+def __DeviceProxy__write_read_attribute(self, attr_name, value, extract_as=ExtractAs.Numpy):
+    return __check_read_attribute(self._write_read_attribute(attr_name, value, extract_as))
+
+def __DeviceProxy__get_property(self, propname, value=None):
+    """
+    get_property(propname, value=None) -> PyTango.DbData
+    
+            Get a (list) property(ies) for a device.
+
+            This method accepts the following types as propname parameter:
+            1. string [in] - single property data to be fetched
+            2. sequence<string> [in] - several property data to be fetched
+            3. PyTango.DbDatum [in] - single property data to be fetched
+            4. PyTango.DbData [in,out] - several property data to be fetched.
+            5. sequence<DbDatum> - several property data to be feteched
+
+            Note: for cases 3, 4 and 5 the 'value' parameter if given, is IGNORED.
+
+            If value is given it must be a PyTango.DbData that will be filled with the
+            property values
+
+        Parameters :
+            - propname : (any) property(ies) name(s)
+            - value : (DbData) (optional, default is None meaning that the
+                      method will create internally a PyTango.DbData and return
+                      it filled with the property values
+
+        Return     : (DbData) object containing the property(ies) value(s). If a
+                     PyTango.DbData is given as parameter, it returns the same
+                     object otherwise a new PyTango.DbData is returned
+
+        Throws     : NonDbDevice, ConnectionFailed (with database),
+                     CommunicationFailed (with database),
+                     DevFailed from database device
+    """
+
+    if type(propname) in types.StringTypes or isinstance(propname, StdStringVector):
+        new_value = value
+        if new_value is None:
+            new_value = DbData()
+        self._get_property(propname, new_value)
+        return DbData_2_dict(new_value)
+    elif isinstance(propname, DbDatum):
+        new_value = DbData()
+        new_value.append(propname)
+        self._get_property(new_value)
+        return DbData_2_dict(new_value)
+    elif operator.isSequenceType(propname):
+        if isinstance(propname, DbData):
+            self._get_property(propname)
+            return DbData_2_dict(propname)
+
+        if type(propname[0]) in types.StringTypes:
+            new_propname = StdStringVector()
+            for i in propname: new_propname.append(i)
+            new_value = value
+            if new_value is None:
+                new_value = DbData()
+            self._get_property(new_propname, new_value)
+            return DbData_2_dict(new_value)
+        elif isinstance(propname[0], DbDatum):
+            new_value = DbData()
+            for i in propname: new_value.append(i)
+            self._get_property(new_value)
+            return DbData_2_dict(new_value)
+
+def __DeviceProxy__put_property(self, value):
+    """
+    put_property(self, value) -> None
+    
+            Insert or update a list of properties for this device.
+            This method accepts the following types as value parameter:
+            1. PyTango.DbDatum - single property data to be inserted
+            2. PyTango.DbData - several property data to be inserted
+            3. sequence<DbDatum> - several property data to be inserted
+            4. dict<str, DbDatum> - keys are property names and value has data to be inserted
+            5. dict<str, seq<str>> - keys are property names and value has data to be inserted
+            6. dict<str, obj> - keys are property names and str(obj) is property value
+
+        Parameters :
+            - value : can be one of the following:
+                1. PyTango.DbDatum - single property data to be inserted
+                2. PyTango.DbData - several property data to be inserted
+                3. sequence<DbDatum> - several property data to be inserted
+                4. dict<str, DbDatum> - keys are property names and value has data to be inserted
+                5. dict<str, seq<str>> - keys are property names and value has data to be inserted
+                6. dict<str, obj> - keys are property names and str(obj) is property value
+
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed
+                    DevFailed from device (DB_SQLError)
+    """
+    if isinstance(value, DbData):
+        pass
+    elif isinstance(value, DbDatum):
+        new_value = DbData()
+        new_value.append(value)
+        value = new_value
+    elif operator.isSequenceType(value) and not type(value) in types.StringTypes:
+        new_value = seq_2_DbData(value)
+    elif operator.isMappingType(value):
+        new_value = DbData()
+        for k, v in value.iteritems():
+            if isinstance(v, DbDatum):
+                new_value.append(v)
+                continue
+            db_datum = DbDatum(k)
+            if operator.isSequenceType(v) and not type(v) in types.StringTypes:
+                seq_2_StdStringVector(v, db_datum.value_string)
+            else:
+                db_datum.value_string.append(str(v))
+            new_value.append(db_datum)
+        value = new_value
+    else:
+        raise TypeError('value must be a PyTango.DbDatum, PyTango.DbData,'\
+                        'a sequence<DbDatum> or a dictionary')
+    return self._put_property(value)
+
+def __DeviceProxy__delete_property(self, value):
+    """
+    delete_property(self, value)
+    
+            Delete a the given of properties for this device.
+            This method accepts the following types as value parameter:
+            1. string [in] - single property to be deleted
+            2. PyTango.DbDatum [in] - single property data to be deleted
+            3. PyTango.DbData [in] - several property data to be deleted
+            4. sequence<string> [in]- several property data to be deleted
+            5. sequence<DbDatum> [in] - several property data to be deleted
+            6. dict<str, obj> [in] - keys are property names to be deleted (values are ignored)
+            7. dict<str, DbDatum> [in] - several DbDatum.name are property names to be
+                                        deleted (keys are ignored)
+
+        Parameters :
+            - value : can be one of the following:
+                1. string [in] - single property data to be deleted
+                2. PyTango.DbDatum [in] - single property data to be deleted
+                3. PyTango.DbData [in] - several property data to be deleted
+                4. sequence<string> [in]- several property data to be deleted
+                5. sequence<DbDatum> [in] - several property data to be deleted
+                6. dict<str, obj> [in] - keys are property names to be deleted (values are ignored)
+                7. dict<str, DbDatum> [in] - several DbDatum.name are property names
+                                            to be deleted (keys are ignored)
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed
+                    DevFailed from device (DB_SQLError)
+    """
+    if isinstance(value, DbData) or isinstance(value, StdStringVector) or \
+       type(value) in types.StringTypes:
+        new_value = value
+    elif isinstance(value, DbDatum):
+        new_value = DbData()
+        new_value.append(value)
+    elif operator.isSequenceType(value):
+        new_value = DbData()
+        for e in value:
+            if isinstance(e, DbDatum):
+                new_value.append(e)
+            else:
+                new_value.append(DbDatum(str(e)))
+    elif operator.isMappingType(value):
+        new_value = DbData()
+        for k, v in value.iteritems():
+            if isinstance(v, DbDatum):
+                new_value.append(v)
+            else:
+                new_value.append(DbDatum(k))
+    else:
+        raise TypeError('value must be a string, PyTango.DbDatum, '\
+                        'PyTango.DbData, a sequence or a dictionary')
+
+    return self._delete_property(new_value)
+
+def __DeviceProxy__get_property_list(self, filter, array=None):
+    """
+    get_property_list(self, filter, array=None) -> obj
+
+            Get the list of property names for the device. The parameter
+            filter allows the user to filter the returned name list. The
+            wildcard character is '*'. Only one wildcard character is
+            allowed in the filter parameter.
+
+        Parameters :
+                - filter[in] : (str) the filter wildcard
+                - array[out] : (sequence obj or None) (optional, default is None)
+                            an array to be filled with the property names. If None
+                            a new list will be created internally with the values.
+
+        Return     : the given array filled with the property names (or a new list
+                    if array is None)
+
+        Throws     : NonDbDevice, WrongNameSyntax,
+                    ConnectionFailed (with database),
+                    CommunicationFailed (with database)
+                    DevFailed from database device
+
+        New in PyTango 7.0.0
+    """
+
+    if array is None:
+        new_array = StdStringVector()
+        self._get_property_list(filter, new_array)
+        return new_array
+
+    if isinstance(array, StdStringVector):
+        self._get_property_list(filter, array)
+        return array
+    elif operator.isSequenceType(array):
+        new_array = StdStringVector()
+        self._get_property_list(filter, new_array)
+        StdStringVector_2_seq(new_array, array)
+        return array
+
+    raise TypeError('array must be a mutable sequence<string>')
+
+def __DeviceProxy__get_attribute_config(self, value):
+    """
+    get_attribute_config( self, name) -> AttributeInfoEx
+
+            Return the attribute configuration for a single attribute.
+
+        Parameters :
+                - name : (str) attribute name
+        Return     : (AttributeInfoEx) Object containing the attribute
+                        information
+
+        Throws     : ConnectionFailed, CommunicationFailed,
+                        DevFailed from device
+        
+        Deprecated: use get_attribute_config_ex instead
+
+    get_attribute_config( self, names) -> AttributeInfoList
+
+            Return the attribute configuration for the list of specified attributes. To get all the
+            attributes pass a sequence containing the constant PyTango.constants.AllAttr
+
+        Parameters :
+                - names : (sequence<str>) attribute names
+        Return     : (AttributeInfoList) Object containing the attributes
+                        information
+
+        Throws     : ConnectionFailed, CommunicationFailed,
+                        DevFailed from device
+
+        Deprecated: use get_attribute_config_ex instead
+    """
+    if isinstance(value, StdStringVector) or type(value) in types.StringTypes:
+        return self._get_attribute_config(value)
+    elif operator.isSequenceType(value):
+        v = seq_2_StdStringVector(value)
+        return self._get_attribute_config(v)
+
+    raise TypeError('value must be a string or a sequence<string>')
+
+def __DeviceProxy__get_attribute_config_ex(self, value):
+    """
+    get_attribute_config_ex( self, name) -> AttributeInfoListEx :
+
+            Return the extended attribute configuration for a single attribute.
+
+        Parameters :
+                - name : (str) attribute name
+        Return     : (AttributeInfoEx) Object containing the attribute
+                        information
+
+        Throws     : ConnectionFailed, CommunicationFailed,
+                        DevFailed from device
+
+    get_attribute_config( self, names) -> AttributeInfoListEx :
+
+            Return the extended attribute configuration for the list of
+            specified attributes. To get all the attributes pass a sequence
+            containing the constant PyTango.constants.AllAttr
+            
+        Parameters :
+                - names : (sequence<str>) attribute names
+        Return     : (AttributeInfoList) Object containing the attributes
+                        information
+
+        Throws     : ConnectionFailed, CommunicationFailed,
+                        DevFailed from device
+    """
+    if isinstance(value, StdStringVector):
+        return self._get_attribute_config_ex(value)
+    elif type(value) in types.StringTypes:
+        v = StdStringVector()
+        v.append(value)
+        return self._get_attribute_config_ex(v)
+    elif operator.isSequenceType(value):
+        v = seq_2_StdStringVector(value)
+        return self._get_attribute_config_ex(v)
+
+    raise TypeError('value must be a string or a sequence<string>')
+
+def __DeviceProxy__set_attribute_config(self, value):
+    """
+    set_attribute_config( self, attr_info) -> None
+
+            Change the attribute configuration for the specified attribute
+
+        Parameters :
+                - attr_info : (AttributeInfo) attribute information
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed,
+                        DevFailed from device
+
+    set_attribute_config( self, attr_info_ex) -> None
+
+            Change the extended attribute configuration for the specified attribute
+
+        Parameters :
+                - attr_info_ex : (AttributeInfoEx) extended attribute information
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed,
+                        DevFailed from device
+
+    set_attribute_config( self, attr_info) -> None
+
+            Change the attributes configuration for the specified attributes
+
+        Parameters :
+                - attr_info : (sequence<AttributeInfo>) attributes information
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed,
+                        DevFailed from device
+
+    set_attribute_config( self, attr_info_ex) -> None
+    
+            Change the extended attributes configuration for the specified attributes
+        
+        Parameters :
+                - attr_info_ex : (sequence<AttributeInfoListEx>) extended
+                                    attributes information
+        Return     : None
+
+        Throws     : ConnectionFailed, CommunicationFailed,
+                        DevFailed from device
+
+    """
+    if isinstance(value, AttributeInfoEx):
+        v = AttributeInfoListEx()
+        v.append(value)
+    elif isinstance(value, AttributeInfo):
+        v = AttributeInfoList()
+        v.append(value)
+    elif isinstance(value, AttributeInfoList):
+        v = value
+    elif isinstance(value, AttributeInfoListEx):
+        v = value
+    elif operator.isSequenceType(value):
+        if not len(value): return
+        if isinstance(value[0], AttributeInfoEx):
+            v = AttributeInfoListEx()
+        elif isinstance(value[0], AttributeInfo):
+            v = AttributeInfoList()
+        else:
+            raise TypeError('value must be a AttributeInfo, AttributeInfoEx, ' \
+                            'sequence<AttributeInfo> or sequence<AttributeInfoEx')
+        for i in value: v.append(i)
+    else:
+        raise TypeError('value must be a AttributeInfo, AttributeInfoEx, ' \
+                        'sequence<AttributeInfo> or sequence<AttributeInfoEx')
+
+    return self._set_attribute_config(v)
+
+def __DeviceProxy__get_event_map(self):
+    """
+    Internal helper method"""
+    if not hasattr(self, '_subscribed_events'):
+        # do it like this instead of self._subscribed_events = dict() to avoid
+        # calling __setattr__ which requests list of tango attributes from device
+        self.__dict__['_subscribed_events'] = dict()
+    return self._subscribed_events
+
+def __DeviceProxy__subscribe_event ( self, attr_name, event_type, cb_or_queuesize, filters=[], stateless=False, extract_as=ExtractAs.Numpy):
+    """
+    subscribe_event(self, attr_name, event, callback, filters=[], stateless=False, extract_as=Numpy) -> int
+
+            The client call to subscribe for event reception in the push model.
+            The client implements a callback method which is triggered when the
+            event is received. Filtering is done based on the reason specified and
+            the event type. For example when reading the state and the reason
+            specified is "change" the event will be fired only when the state
+            changes. Events consist of an attribute name and the event reason.
+            A standard set of reasons are implemented by the system, additional
+            device specific reasons can be implemented by device servers programmers.
+
+        Parameters :
+            - attr_name : (str) The device attribute name which will be sent
+                          as an event e.g. "current".
+            - event_type: (EventType) Is the event reason and must be on the enumerated values:
+                            * EventType.CHANGE_EVENT
+                            * EventType.PERIODIC_EVENT
+                            * EventType.ARCHIVE_EVENT
+                            * EventType.ATTR_CONF_EVENT
+                            * EventType.DATA_READY_EVENT
+                            * EventType.USER_EVENT
+            - callback  : (callable) Is any callable object or an object with a
+                          callable "push_event" method.
+            - filters   : (sequence<str>) A variable list of name,value pairs
+                          which define additional filters for events.
+            - stateless : (bool) When the this flag is set to false, an exception will
+                          be thrown when the event subscription encounters a problem.
+                          With the stateless flag set to true, the event subscription
+                          will always succeed, even if the corresponding device server
+                          is not running. The keep alive thread will try every 10
+                          seconds to subscribe for the specified event. At every
+                          subscription retry, a callback is executed which contains
+                          the corresponding exception
+            - extract_as : (ExtractAs)
+
+        Return     : An event id which has to be specified when unsubscribing
+                     from this event.
+
+        Throws     : EventSystemFailed
+
+
+    subscribe_event(self, attr_name, event, queuesize, filters=[], stateless=False ) -> int
+
+            The client call to subscribe for event reception in the pull model.
+            Instead of a callback method the client has to specify the size of the
+            event reception buffer.
+            The event reception buffer is implemented as a round robin buffer. This
+            way the client can set-up different ways to receive events:
+                * Event reception buffer size = 1 : The client is interested only
+                  in the value of the last event received. All other events that
+                  have been received since the last reading are discarded.
+                * Event reception buffer size > 1 : The client has chosen to keep
+                  an event history of a given size. When more events arrive since
+                  the last reading, older events will be discarded.
+                * Event reception buffer size = ALL_EVENTS : The client buffers all
+                  received events. The buffer size is unlimited and only restricted
+                  by the available memory for the client.
+
+            All other parameters are similar to the descriptions given in the
+            other subscribe_event() version.
+    """
+    if callable(cb_or_queuesize):
+        cb = __CallBackPushEvent()
+        cb.push_event = cb_or_queuesize
+    elif hasattr(cb_or_queuesize, "push_event") and callable(cb_or_queuesize.push_event):
+        cb = __CallBackPushEvent()
+        cb.push_event = cb_or_queuesize.push_event
+    elif operator.isNumberType(cb_or_queuesize):
+        cb = cb_or_queuesize # queuesize
+    else:
+        raise TypeError("Parameter cb_or_queuesize should be a number, a" + \
+                    " callable object or an object with a 'push_event' method.")
+
+    event_id = self.__subscribe_event(attr_name, event_type, cb, filters, stateless, extract_as)
+
+    se = self.__get_event_map()
+    se[event_id] = (cb, event_type, attr_name)
+    return event_id
+
+def __DeviceProxy__unsubscribe_event(self, event_id):
+    """
+    unsubscribe_event(self, event_id) -> None
+
+            Unsubscribes a client from receiving the event specified by event_id.
+
+        Parameters :
+            - event_id   : (int) is the event identifier returned by the
+                            DeviceProxy::subscribe_event(). Unlike in
+                            TangoC++ we chech that the event_id has been
+                            subscribed in this DeviceProxy.
+
+        Return     : None
+
+        Throws     : EventSystemFailed
+    """
+    se = self.__get_event_map()
+    if event_id not in se:
+        raise IndexError("This device proxy does not own this subscription " + str(event_id))
+    self.__unsubscribe_event(event_id)
+    del se[event_id]
+
+def __DeviceProxy__unsubscribe_event_all(self):
+    se = self.__get_event_map()
+    for event_id in se:
+        try:
+            self.__unsubscribe_event(event_id)
+        except Exception:
+            pass # @todo print or something, but not rethrow
+    se.clear()
+
+def __DeviceProxy__get_events(self, event_id, callback=None, extract_as=ExtractAs.Numpy):
+    """
+    get_events( event_id, callback=None, extract_as=Numpy) -> None
+
+        The method extracts all waiting events from the event reception buffer.
+
+        If callback is not None, it is executed for every event. During event
+        subscription the client must have chosen the pull model for this event.
+        The callback will receive a parameter of type EventData,
+        AttrConfEventData or DataReadyEventData depending on the type of the
+        event (event_type parameter of subscribe_event).
+
+        If callback is None, the method extracts all waiting events from the
+        event reception buffer. The returned event_list is a vector of
+        EventData, AttrConfEventData or DataReadyEventData pointers, just
+        the same data the callback would have received.
+
+        Parameters :
+            - event_id : (int) is the event identifier returned by the
+                DeviceProxy.subscribe_event() method.
+                
+            - callback : (callable) Any callable object or any object with a "push_event"
+                         method.
+
+            - extract_as: (ExtractAs)
+
+        Return     : None
+
+        Throws     : EventSystemFailed
+
+        See Also   : subscribe_event
+
+        New in PyTango 7.0.0
+    """
+    if callback is None:
+        queuesize, event_type, attr_name = self.__get_event_map().get(event_id, (None, None, None))
+        if event_type is None:
+            raise ValueError("Invalid event_id. You are not subscribed to event %s." % str(event_id))
+        if event_type in [  EventType.CHANGE_EVENT,
+                            EventType.QUALITY_EVENT,
+                            EventType.PERIODIC_EVENT,
+                            EventType.ARCHIVE_EVENT,
+                            EventType.USER_EVENT ]:
+            return self.__get_data_events(event_id, extract_as)
+        elif event_type in [ EventType.ATTR_CONF_EVENT ]:
+            return self.__get_attr_conf_events(event_id, extract_as)
+        elif event_type in [ EventType.DATA_READY_EVENT ]:
+            return self.__get_data_ready_events(event_id, extract_as)
+        else:
+            assert (False)
+            raise ValueError("Unknown event_type: " + str(event_type))
+    elif callable(callback):
+        cb = __CallBackPushEvent()
+        cb.push_event = callback
+        return self.__get_callback_events(event_id, cb, extract_as)
+    elif hasattr(callback, 'push_event') and callable(callback.push_event):
+        cb = __CallBackPushEvent()
+        cb.push_event = callback.push_event
+        return self.__get_callback_events(event_id, cb, extract_as)
+    else:
+        raise TypeError("Parameter 'callback' should be None, a callable object or an object with a 'push_event' method.")
+
+def __DeviceProxy__str(self):
+    if not hasattr(self, '_dev_class'):
+        try:
+            self.__dict__["_dev_class"] = self.info().dev_class
+        except:
+            return "DeviceProxy(%s)" % self.dev_name()
+    return "%s(%s)" % (self._dev_class, self.dev_name())
+    
+def __init_DeviceProxy():
+    DeviceProxy.__getattr__ = __DeviceProxy__getattr
+    DeviceProxy.__setattr__ = __DeviceProxy__setattr
+    DeviceProxy.__del__ = __DeviceProxy__del
+    DeviceProxy.__getitem__ = __DeviceProxy__getitem
+    DeviceProxy.__setitem__ = __DeviceProxy__setitem
+    DeviceProxy.__contains__ = __DeviceProxy__contains
+
+    DeviceProxy._getAttributeNames = __DeviceProxy__getAttributeNames
+
+    DeviceProxy.__refresh_cmd_cache = __DeviceProxy__refresh_cmd_cache
+    DeviceProxy.__refresh_attr_cache = __DeviceProxy__refresh_attr_cache
+
+    DeviceProxy.read_attribute = __DeviceProxy__read_attribute
+    DeviceProxy.read_attributes_asynch = __DeviceProxy__read_attributes_asynch
+    DeviceProxy.read_attribute_asynch = __DeviceProxy__read_attribute_asynch
+    DeviceProxy.read_attribute_reply = __DeviceProxy__read_attribute_reply
+    DeviceProxy.write_attributes_asynch = __DeviceProxy__write_attributes_asynch
+    DeviceProxy.write_attribute_asynch = __DeviceProxy__write_attribute_asynch
+    DeviceProxy.write_attribute_reply = DeviceProxy.write_attributes_reply
+    DeviceProxy.write_read_attribute = __DeviceProxy__write_read_attribute
+
+    DeviceProxy.get_property = __DeviceProxy__get_property
+    DeviceProxy.put_property = __DeviceProxy__put_property
+    DeviceProxy.delete_property = __DeviceProxy__delete_property
+    DeviceProxy.get_property_list = __DeviceProxy__get_property_list
+    DeviceProxy.get_attribute_config = __DeviceProxy__get_attribute_config
+    DeviceProxy.get_attribute_config_ex = __DeviceProxy__get_attribute_config_ex
+    DeviceProxy.set_attribute_config = __DeviceProxy__set_attribute_config
+
+    DeviceProxy.__get_event_map = __DeviceProxy__get_event_map
+    DeviceProxy.subscribe_event = __DeviceProxy__subscribe_event
+    DeviceProxy.unsubscribe_event = __DeviceProxy__unsubscribe_event
+    DeviceProxy.__unsubscribe_event_all = __DeviceProxy__unsubscribe_event_all
+    DeviceProxy.get_events = __DeviceProxy__get_events
+    DeviceProxy.__str__ = __DeviceProxy__str
+    DeviceProxy.__repr__ = __DeviceProxy__str
+
+def __doc_DeviceProxy():
+    def document_method(method_name, desc, append=True):
+        return __document_method(DeviceProxy, method_name, desc, append)
+
+    DeviceProxy.__doc__ = """
+    DeviceProxy is the high level Tango object which provides the client with
+    an easy-to-use interface to TANGO devices. DeviceProxy provides interfaces
+    to all TANGO Device interfaces.The DeviceProxy manages timeouts, stateless
+    connections and reconnection if the device server is restarted. To create
+    a DeviceProxy, a Tango Device name must be set in the object constructor.
+
+    Example :
+       dev = PyTango.DeviceProxy("sys/tg_test/1")
+    """
+
+#-------------------------------------
+#   General methods
+#-------------------------------------
+
+    document_method("info", """
+    info(self) -> DeviceInfo
+
+            A method which returns information on the device
+
+        Parameters : None
+        Return     : (DeviceInfo) object
+        Example    :
+                dev_info = dev.info()
+                print dev_info.dev_class
+                print dev_info.server_id
+                print dev_info.server_host
+                print dev_info.server_version
+                print dev_info.doc_url
+                print dev_info.dev_type
+
+            All DeviceInfo fields are strings except for the server_version
+            which is an integer"
+    """ )
+
+    document_method("get_device_db", """
+    get_device_db(self) -> Database
+
+            Returns the internal database reference
+
+        Parameters : None
+        Return     : (Database) object
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("status", """
+    status(self) -> str
+
+            A method which returns the status of the device as a string.
+
+        Parameters : None
+        Return     : (str) describing the device status
+    """ )
+
+    document_method("state", """
+    state(self) -> DevState
+
+            A method which returns the state of the device.
+
+        Parameters : None
+        Return     : (DevState) constant
+        Example :
+                dev_st = dev.state()
+                if dev_st == DevState.ON : ...
+    """ )
+
+    document_method("adm_name", """
+    adm_name(self) -> str
+
+            Return the name of the corresponding administrator device. This is
+            useful if you need to send an administration command to the device
+            server, e.g restart it
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("description", """
+    description(self) -> str
+
+            Get device description.
+
+        Parameters : None
+        Return     : (str) describing the device
+    """ )
+
+    document_method("name", """
+    name(self) -> str
+
+            Return the device name from the device itself.
+    """ )
+
+    document_method("alias", """
+    alias(self) -> str
+
+            Return the device alias if one is defined.
+            Otherwise, throws exception.
+    """ )
+
+    document_method("ping", """
+    ping(self) -> int
+
+            A method which sends a ping to the device
+
+        Parameters : None
+        Return     : (int) time elapsed in milliseconds
+        Throw      : exception if device is not alive
+    """ )
+
+    document_method("black_box", """
+    black_box(self, n) -> sequence<str>
+
+            Get the last commands executed on the device server
+
+        Parameters :
+            - n : n number of commands to get
+        Return     : (sequence<str>) sequence of strings containing the date, time,
+                     command and from which client computer the command
+                     was executed
+        Example :
+                print black_box(4)
+    """ )
+
+#-------------------------------------
+#   Device methods
+#-------------------------------------
+
+    document_method("command_query", """
+    command_query(self, command) -> CommandInfo
+
+            Query the device for information about a single command.
+
+        Parameters :
+                - command : (str) command name
+        Return     : (CommandInfo) object
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device
+        Example :
+                com_info = dev.command_query(""DevString"")
+                print com_info.cmd_name
+                print com_info.cmd_tag
+                print com_info.in_type
+                print com_info.out_type
+                print com_info.in_type_desc
+                print com_info.out_type_desc
+                print com_info.disp_level
+        See CommandInfo documentation string form more detail
+    """ )
+
+    document_method("command_list_query", """
+    command_list_query(self) -> sequence<CommandInfo>
+
+            Query the device for information on all commands.
+
+        Parameters : None
+        Return     : (CommandInfoList) Sequence of CommandInfo objects
+    """ )
+
+    document_method("import_info", """
+    import_info(self) -> DbDevImportInfo
+
+            Query the device for import info from the database.
+
+        Parameters : None
+        Return     : (DbDevImportInfo)
+        Example :
+                dev_import = dev.import_info()
+                print dev_import.name
+                print dev_import.exported
+                print dev_ior.ior
+                print dev_version.version
+
+        All DbDevImportInfo fields are strings except for exported which
+        is an integer"
+    """ )
+
+#-------------------------------------
+#   Property methods
+#-------------------------------------
+    # get_property -> in code
+    # put_property -> in code
+    # delete_property -> in code
+    # get_property_list -> in code
+
+#-------------------------------------
+#   Attribute methods
+#-------------------------------------
+    document_method("get_attribute_list", """
+    get_attribute_list(self) -> sequence<str>
+
+            Return the names of all attributes implemented for this device.
+
+        Parameters : None
+        Return     : sequence<str>
+
+        Throws     : ConnectionFailed, CommunicationFailed,
+                     DevFailed from device
+    """ )
+
+    # get_attribute_config -> in code
+    # get_attribute_config_ex -> in code
+
+    document_method("attribute_query", """
+    attribute_query(self, attr_name) -> AttributeInfoEx
+
+            Query the device for information about a single attribute.
+
+        Parameters :
+                - attr_name :(str) the attribute name
+        Return     : (AttributeInfoEx) containing the attribute
+                     configuration
+
+        Throws     : ConnectionFailed, CommunicationFailed,
+                     DevFailed from device
+    """ )
+
+    document_method("attribute_list_query", """
+    attribute_list_query(self) -> sequence<AttributeInfo>
+
+            Query the device for info on all attributes. This method returns
+            a sequence of PyTango.AttributeInfo.
+
+        Parameters : None
+        Return     : (sequence<AttributeInfo>) containing the
+                     attributes configuration
+
+        Throws     : ConnectionFailed, CommunicationFailed,
+                     DevFailed from device
+    """ )
+
+    document_method("attribute_list_query_ex", """
+    attribute_list_query_ex(self) -> sequence<AttributeInfoEx>
+
+            Query the device for info on all attributes. This method returns
+            a sequence of PyTango.AttributeInfoEx.
+
+        Parameters : None
+        Return     : (sequence<AttributeInfoEx>) containing the
+                     attributes configuration
+
+        Throws     : ConnectionFailed, CommunicationFailed,
+                     DevFailed from device
+    """ )
+
+    # set_attribute_config -> in code
+
+    document_method("read_attribute", """
+    read_attribute(self, attr_name, extract_as=ExtractAs.Numpy) -> DeviceAttribute
+
+            Read a single attribute.
+
+        Parameters :
+            - attr_name  : (str) The name of the attribute to read.
+            - extract_as : (ExtractAs) Defaults to numpy.
+        Return     : (DeviceAttribute)
+
+        Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device
+    """ )
+
+    document_method("read_attributes", """
+        read_attributes(self, attr_names, extract_as=ExtractAs.Numpy) -> sequence<DeviceAttribute>
+
+                Read the list of specified attributes.
+
+            Parameters :
+                    - attr_names : (sequence<str>) A list of attributes to read.
+                    - extract_as : (ExtractAs) Defaults to numpy.
+            Return     : (sequence<DeviceAttribute>)
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device
+    """ )
+
+    document_method("write_attribute", """
+        write_attribute(self, attr_name, value) -> None
+        write_attribute(self, attr_info, value) -> None
+
+                Write a single attribute.
+
+            Parameters :
+                    - attr_name : (str) The name of the attribute to write.
+                    - attr_info : (AttributeInfo)
+                    - value : The value. For non SCALAR attributes it may be any sequence of sequences.
+
+            Throws     : ConnectionFailed, CommunicationFailed, DeviceUnlocked, DevFailed from device
+    """ )
+
+    document_method("write_attributes", """
+    write_attributes(self, name_val) -> None
+
+            Write the specified attributes.
+
+        Parameters :
+                - name_val: A list of pairs (attr_name, value). See write_attribute
+
+        Throws     : ConnectionFailed, CommunicationFailed, DeviceUnlocked,
+                     DevFailed or NamedDevFailedList from device
+    """ )
+
+    document_method("write_read_attribute", """
+    write_read_attribute(self, attr_name, value, extract_as=ExtractAs.Numpy) -> DeviceAttribute
+
+            Write then read a single attribute in a single network call.
+            By default (serialisation by device), the execution of this call in
+            the server can't be interrupted by other clients.
+
+        Parameters : see write_attribute(attr_name, value)
+        Return     : A PyTango.DeviceAttribute object.
+
+        Throws     : ConnectionFailed, CommunicationFailed, DeviceUnlocked,
+                     DevFailed from device, WrongData
+
+        New in PyTango 7.0.0
+    """ )
+
+#-------------------------------------
+#   History methods
+#-------------------------------------
+    document_method("command_history", """
+    command_history(self, cmd_name, depth) -> sequence<DeviceDataHistory>
+
+            Retrieve command history from the command polling buffer. See
+            chapter on Advanced Feature for all details regarding polling
+
+        Parameters :
+           - cmd_name  : (str) Command name.
+           - depth     : (int) The wanted history depth.
+        Return     : This method returns a vector of DeviceDataHistory types.
+
+        Throws     : NonSupportedFeature, ConnectionFailed,
+                     CommunicationFailed, DevFailed from device
+    """ )
+
+    document_method("attribute_history", """
+    attribute_history(self, attr_name, depth, extract_as=ExtractAs.Numpy) -> sequence<DeviceAttributeHistory>
+
+            Retrieve attribute history from the attribute polling buffer. See
+            chapter on Advanced Feature for all details regarding polling
+
+        Parameters :
+           - attr_name  : (str) Attribute name.
+           - depth      : (int) The wanted history depth.
+           - extract_as : (ExtractAs)
+
+        Return     : This method returns a vector of DeviceAttributeHistory types.
+
+        Throws     : NonSupportedFeature, ConnectionFailed,
+                     CommunicationFailed, DevFailed from device
+    """ )
+
+#-------------------------------------
+#   Polling administration methods
+#-------------------------------------
+
+    document_method("polling_status", """
+    polling_status(self) -> sequence<str>
+
+            Return the device polling status.
+
+        Parameters : None
+        Return     : (sequence<str>) One string for each polled command/attribute.
+                     Each string is multi-line string with
+                        - attribute/command name
+                        - attribute/command polling period in milliseconds
+                        - attribute/command polling ring buffer
+                        - time needed for last attribute/command execution in milliseconds
+                        - time since data in the ring buffer has not been updated
+                        - delta time between the last records in the ring buffer
+                        - exception parameters in case of the last execution failed
+    """ )
+
+    document_method("poll_command", """
+    poll_command(self, cmd_name, period) -> None
+
+            Add a command to the list of polled commands.
+
+        Parameters :
+            - cmd_name : (str) command name
+            - period   : (int) polling period in milliseconds
+        Return     : None
+    """ )
+
+    document_method("poll_attribute", """
+    poll_attribute(self, attr_name, period) -> None
+
+            Add an attribute to the list of polled attributes.
+
+        Parameters :
+            - attr_name : (str) attribute name
+            - period    : (int) polling period in milliseconds
+        Return     : None
+    """ )
+
+    document_method("get_command_poll_period", """
+    get_command_poll_period(self, cmd_name) -> int
+
+            Return the command polling period.
+
+        Parameters :
+            - cmd_name : (str) command name
+        Return     : polling period in milliseconds
+    """ )
+
+    document_method("get_attribute_poll_period", """
+    get_attribute_poll_period(self, attr_name) -> int
+
+            Return the attribute polling period.
+
+        Parameters :
+            - attr_name : (str) attribute name
+        Return     : polling period in milliseconds
+    """ )
+
+    document_method("is_command_polled", """
+    is_command_polled(self, cmd_name) -> bool
+
+            True if the command is polled.
+
+        Parameters :
+            - cmd_name : (str) command name
+        Return     : boolean value
+    """ )
+
+    document_method("is_attribute_polled", """
+    is_attribute_polled(self, attr_name) -> bool
+
+            True if the attribute is polled.
+
+        Parameters :
+            - attr_name : (str) attribute name
+        Return     : boolean value
+    """ )
+
+    document_method("stop_poll_command", """
+    stop_poll_command(self, cmd_name) -> None
+
+            Remove a command from the list of polled commands.
+
+        Parameters :
+            - cmd_name : (str) command name
+        Return     : None
+    """ )
+
+    document_method("stop_poll_attribute", """
+    stop_poll_attribute(self, attr_name) -> None
+
+            Remove an attribute from the list of polled attributes.
+
+        Parameters :
+            - attr_name : (str) attribute name
+        Return     : None
+    """ )
+
+#-------------------------------------
+#   Asynchronous methods
+#-------------------------------------
+
+    # read_attribute_asynch -> in code
+    # read_attributes_asynch -> in code
+    # read_attribute_reply -> in code
+    document_method("read_attributes_reply", """
+    read_attributes_reply(self, id, extract_as=ExtractAs.Numpy) -> DeviceAttribute
+
+            Check if the answer of an asynchronous read_attribute is
+            arrived (polling model).
+
+        Parameters :
+            - id         : (int) is the asynchronous call identifier.
+            - extract_as : (ExtractAs)
+        Return     : If the reply is arrived and if it is a valid reply, it is
+                     returned to the caller in a list of DeviceAttribute. If the
+                     reply is an exception, it is re-thrown by this call. An
+                     exception is also thrown in case of the reply is not yet
+                     arrived.
+
+        Throws     : AsynCall, AsynReplyNotArrived, ConnectionFailed,
+                     CommunicationFailed, DevFailed from device
+
+        New in PyTango 7.0.0
+
+
+    read_attributes_reply(self, id, timeout, extract_as=ExtractAs.Numpy) -> DeviceAttribute
+
+            Check if the answer of an asynchronous read_attributes is arrived (polling model).
+
+        Parameters :
+            - id         : (int) is the asynchronous call identifier.
+            - timeout    : (int)
+            - extract_as : (ExtractAs)
+        Return     : If the reply is arrived and if it is a valid reply, it is
+                     returned to the caller in a list of DeviceAttribute. If the
+                     reply is an exception, it is re-thrown by this call. If the
+                     reply is not yet arrived, the call will wait (blocking the
+                     process) for the time specified in timeout. If after
+                     timeout milliseconds, the reply is still not there, an
+                     exception is thrown. If timeout is set to 0, the call waits
+                     until the reply arrived.
+
+        Throws     : AsynCall, AsynReplyNotArrived, ConnectionFailed,
+                     CommunicationFailed, DevFailed from device
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("pending_asynch_call", """
+    pending_asynch_call(self) -> int
+
+            Return number of device asynchronous pending requests"
+
+        New in PyTango 7.0.0
+    """ )
+
+    # write_attributes_asynch -> in code
+
+    document_method("write_attributes_reply", """
+    write_attributes_reply(self, id) -> None
+
+            Check if the answer of an asynchronous write_attributes is arrived
+            (polling model). If the reply is arrived and if it is a valid reply,
+            the call returned. If the reply is an exception, it is re-thrown by
+            this call. An exception is also thrown in case of the reply is not
+            yet arrived.
+
+        Parameters :
+            - id : (int) the asynchronous call identifier.
+        Return     : None
+
+        Throws     : AsynCall, AsynReplyNotArrived, CommunicationFailed, DevFailed from device.
+
+        New in PyTango 7.0.0
+
+    write_attributes_reply(self, id, timeout) -> None
+
+            Check if the answer of an asynchronous write_attributes is arrived
+            (polling model). id is the asynchronous call identifier. If the
+            reply is arrived and if it is a valid reply, the call returned. If
+            the reply is an exception, it is re-thrown by this call. If the
+            reply is not yet arrived, the call will wait (blocking the process)
+            for the time specified in timeout. If after timeout milliseconds,
+            the reply is still not there, an exception is thrown. If timeout is
+            set to 0, the call waits until the reply arrived.
+        Parameters :
+            - id      : (int) the asynchronous call identifier.
+            - timeout : (int)
+        Return     : None
+
+        Throws     : AsynCall, AsynReplyNotArrived, CommunicationFailed, DevFailed from device.
+
+        New in PyTango 7.0.0
+    """ )
+
+#-------------------------------------
+#   Logging administration methods
+#-------------------------------------
+
+    document_method("add_logging_target", """
+    add_logging_target(self, target_type_target_name) -> None
+
+            Adds a new logging target to the device.
+
+            The target_type_target_name input parameter must follow the
+            format: target_type::target_name. Supported target types are:
+            console, file and device. For a device target, the target_name
+            part of the target_type_target_name parameter must contain the
+            name of a log consumer device (as defined in A.8). For a file
+            target, target_name is the full path to the file to log to. If
+            omitted, the device's name is used to build the file name
+            (which is something like domain_family_member.log). Finally, the
+            target_name part of the target_type_target_name input parameter
+            is ignored in case of a console target and can be omitted.
+
+        Parameters :
+            - target_type_target_name : (str) logging target
+        Return     : None
+
+        Throws     : DevFailed from device
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("remove_logging_target", """
+    remove_logging_target(self, target_type_target_name) -> None
+
+            Removes a logging target from the device's target list.
+
+            The target_type_target_name input parameter must follow the
+            format: target_type::target_name. Supported target types are:
+            console, file and device. For a device target, the target_name
+            part of the target_type_target_name parameter must contain the
+            name of a log consumer device (as defined in ). For a file
+            target, target_name is the full path to the file to remove.
+            If omitted, the default log file is removed. Finally, the
+            target_name part of the target_type_target_name input parameter
+            is ignored in case of a console target and can be omitted.
+            If target_name is set to '*', all targets of the specified
+            target_type are removed.
+
+        Parameters :
+            - target_type_target_name : (str) logging target
+        Return     : None
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("get_logging_target", """
+    get_logging_target(self) -> sequence<str>
+
+            Returns a sequence of string containing the current device's
+            logging targets. Each vector element has the following format:
+            target_type::target_name. An empty sequence is returned is the
+            device has no logging targets.
+
+        Parameters : None
+        Return     : a squence<str> with the logging targets
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("get_logging_level", """
+    get_logging_level(self) -> int
+
+            Returns the current device's logging level, where:
+                - 0=OFF
+                - 1=FATAL
+                - 2=ERROR
+                - 3=WARNING
+                - 4=INFO
+                - 5=DEBUG
+
+        Parameters :None
+        Return     : (int) representing the current logging level
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("set_logging_level", """
+    set_logging_level(self, (int)level) -> None
+
+            Changes the device's logging level, where:
+                - 0=OFF
+                - 1=FATAL
+                - 2=ERROR
+                - 3=WARNING
+                - 4=INFO
+                - 5=DEBUG
+
+        Parameters :
+            - level : (int) logging level
+        Return     : None
+
+        New in PyTango 7.0.0
+    """ )
+
+#-------------------------------------
+#   Event methods
+#-------------------------------------
+
+    # subscribe_event -> in code
+    # unsubscribe_event -> in code
+    # get_events -> in code
+
+    document_method("event_queue_size", """
+    event_queue_size(self, event_id) -> int
+
+            Returns the number of stored events in the event reception
+            buffer. After every call to DeviceProxy.get_events(), the event
+            queue size is 0. During event subscription the client must have
+            chosen the 'pull model' for this event. event_id is the event
+            identifier returned by the DeviceProxy.subscribe_event() method.
+
+        Parameters :
+            - event_id : (int) event identifier
+        Return     : an integer with the queue size
+
+        Throws     : EventSystemFailed
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("get_last_event_date", """
+    get_last_event_date(self, event_id) -> TimeVal
+
+            Returns the arrival time of the last event stored in the event
+            reception buffer. After every call to DeviceProxy:get_events(),
+            the event reception buffer is empty. In this case an exception
+            will be returned. During event subscription the client must have
+            chosen the 'pull model' for this event. event_id is the event
+            identifier returned by the DeviceProxy.subscribe_event() method.
+
+        Parameters :
+            - event_id : (int) event identifier
+        Return     : (PyTango.TimeVal) representing the arrival time
+
+        Throws     : EventSystemFailed
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("is_event_queue_empty", """
+    is_event_queue_empty(self, event_id) -> bool
+
+            Returns true when the event reception buffer is empty. During
+            event subscription the client must have chosen the 'pull model'
+            for this event. event_id is the event identifier returned by the
+            DeviceProxy.subscribe_event() method.
+
+            Parameters :
+                - event_id : (int) event identifier
+            Return     : (bool) True if queue is empty or False otherwise
+
+            Throws     : EventSystemFailed
+
+            New in PyTango 7.0.0
+    """ )
+
+#-------------------------------------
+#   Locking methods
+#-------------------------------------
+    document_method("lock", """
+    lock(self, (int)lock_validity) -> None
+
+            Lock a device. The lock_validity is the time (in seconds) the
+            lock is kept valid after the previous lock call. A default value
+            of 10 seconds is provided and should be fine in most cases. In
+            case it is necessary to change the lock validity, it's not
+            possible to ask for a validity less than a minimum value set to
+            2 seconds. The library provided an automatic system to
+            periodically re lock the device until an unlock call. No code is
+            needed to start/stop this automatic re-locking system. The
+            locking system is re-entrant. It is then allowed to call this
+            method on a device already locked by the same process. The
+            locking system has the following features:
+
+              * It is impossible to lock the database device or any device
+                server process admin device
+              * Destroying a locked DeviceProxy unlocks the device
+              * Restarting a locked device keeps the lock
+              * It is impossible to restart a device locked by someone else
+              * Restarting a server breaks the lock
+
+            A locked device is protected against the following calls when
+            executed by another client:
+
+              * command_inout call except for device state and status
+                requested via command and for the set of commands defined as
+                allowed following the definition of allowed command in the
+                Tango control access schema.
+              * write_attribute call
+              * write_read_attribute call
+              * set_attribute_config call
+
+        Parameters :
+            - lock_validity : (int) lock validity time in seconds
+                                (optional, default value is
+                                PyTango.constants.DEFAULT_LOCK_VALIDITY)
+        Return     : None
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("unlock", """
+    unlock(self, (bool)force) -> None
+
+            Unlock a device. If used, the method argument provides a back
+            door on the locking system. If this argument is set to true,
+            the device will be unlocked even if the caller is not the locker.
+            This feature is provided for administration purpopse and should
+            be used very carefully. If this feature is used, the locker will
+            receive a DeviceUnlocked during the next call which is normally
+            protected by the locking Tango system.
+
+        Parameters :
+            - force : (bool) force unlocking even if we are not the
+                      locker (optional, default value is False)
+        Return     : None
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("locking_status", """
+    locking_status(self) -> str
+
+            This method returns a plain string describing the device locking
+            status. This string can be:
+
+              * 'Device <device name> is not locked' in case the device is
+                not locked
+              * 'Device <device name> is locked by CPP or Python client with
+                PID <pid> from host <host name>' in case the device is
+                locked by a CPP client
+              * 'Device <device name> is locked by JAVA client class
+                <main class> from host <host name>' in case the device is
+                locked by a JAVA client
+
+        Parameters : None
+        Return     : a string representing the current locking status
+
+        New in PyTango 7.0.0"
+    """ )
+
+    document_method("is_locked", """
+    is_locked(self) -> bool
+
+            Returns True if the device is locked. Otherwise, returns False.
+
+        Parameters : None
+        Return     : (bool) True if the device is locked. Otherwise, False
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("is_locked_by_me", """
+    is_locked_by_me(self) -> bool
+
+            Returns True if the device is locked by the caller. Otherwise,
+            returns False (device not locked or locked by someone else)
+
+        Parameters : None
+        Return     : (bool) True if the device is locked by us.
+                        Otherwise, False
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("get_locker", """
+    get_locker(self, lockinfo) -> bool
+
+            If the device is locked, this method returns True an set some
+            locker process informations in the structure passed as argument.
+            If the device is not locked, the method returns False.
+
+        Parameters :
+            - lockinfo [out] : (PyTango.LockInfo) object that will be filled
+                                with lock informantion
+        Return     : (bool) True if the device is locked by us.
+                     Otherwise, False
+
+        New in PyTango 7.0.0
+    """ )
+
+def init(doc=True):
+    __init_DeviceProxy()
+    if doc:
+        __doc_DeviceProxy()
diff --git a/PyTango/device_server.py b/PyTango/device_server.py
new file mode 100644
index 0000000..b22ea4e
--- /dev/null
+++ b/PyTango/device_server.py
@@ -0,0 +1,2202 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = [ "ChangeEventProp", "PeriodicEventProp", "ArchiveEventProp",
+            "AttributeAlarm", "EventProperties",
+            "AttributeConfig", "AttributeConfig_2", "AttributeConfig_3"]
+
+__docformat__ = "restructuredtext"
+
+import copy
+import operator
+import types
+
+import _PyTango
+from _PyTango import StdStringVector, StdDoubleVector
+from _PyTango import DeviceImpl, Device_3Impl, Device_4Impl
+from _PyTango import Attribute, WAttribute, MultiAttribute
+from _PyTango import Attr
+from _PyTango import Logger
+from _PyTango import UserDefaultAttrProp
+
+from utils import seq_2_StdStringVector, seq_2_StdDoubleVector
+from utils import document_method as __document_method
+from utils import copy_doc
+
+import log4tango
+
+class AttributeAlarm(object):
+    """This class represents the python interface for the Tango IDL object
+    AttributeAlarm."""
+    
+    def __init__(self):
+        self.min_alarm = ''
+        self.max_alarm = ''
+        self.min_warning = ''
+        self.max_warning = ''
+        self.delta_t = ''
+        self.delta_val = ''
+        self.extensions = []
+
+class ChangeEventProp(object):
+    """This class represents the python interface for the Tango IDL object
+    ChangeEventProp."""
+    
+    def __init__(self):
+        self.rel_change = ''
+        self.abs_change = ''
+        self.extensions = []
+
+class PeriodicEventProp(object):
+    """This class represents the python interface for the Tango IDL object
+    PeriodicEventProp."""
+    
+    def __init__(self):
+        self.period = ''
+        self.extensions = []
+
+class ArchiveEventProp(object):
+    """This class represents the python interface for the Tango IDL object
+    ArchiveEventProp."""
+    
+    def __init__(self):
+        self.rel_change = ''
+        self.abs_change = ''
+        self.period = ''
+        self.extensions = []
+
+class EventProperties(object):
+    """This class represents the python interface for the Tango IDL object
+    EventProperties."""
+    
+    def __init__(self):
+        self.ch_event = ChangeEventProp()
+        self.per_event = PeriodicEventProp()
+        self.arch_event = ArchiveEventProp()
+
+def __init_attr_config(attr_cfg):
+    """Helper function to initialize attribute config objects"""
+    attr_cfg.name = ''
+    attr_cfg.writable = -1
+    attr_cfg.data_format = -1
+    attr_cfg.data_type = -1
+    attr_cfg.max_dim_x = -1
+    attr_cfg.max_dim_y = -1
+    attr_cfg.description = -1
+    attr_cfg.label = ''
+    attr_cfg.unit = ''
+    attr_cfg.standard_unit = ''
+    attr_cfg.display_unit = ''
+    attr_cfg.format = ''
+    attr_cfg.min_value = ''
+    attr_cfg.max_value = ''
+    attr_cfg.writable_attr_name = ''
+    attr_cfg.extensions = []
+    
+class AttributeConfig(object):
+    """This class represents the python interface for the Tango IDL object
+    AttributeConfig."""
+    
+    def __init__(self):
+        __init_attr_config(self)
+        self.min_alarm = ''
+        self.max_alarm = ''
+        
+class AttributeConfig_2(object):
+    """This class represents the python interface for the Tango IDL object
+    AttributeConfig_2."""
+
+    def __init__(self):
+        __init_attr_config(self)
+        self.level = -1
+        self.min_alarm = ''
+        self.max_alarm = ''
+        
+class AttributeConfig_3(object):
+    """This class represents the python interface for the Tango IDL object
+    AttributeConfig_3."""
+
+    def __init__(self):
+        __init_attr_config(self)
+        self.level = -1
+        self.att_alarm = AttributeAlarm()
+        self.event_prop = EventProperties()
+        self.sys_extensions = []
+
+def __DeviceImpl__get_device_class(self):
+    try:
+        return self._device_class_instance
+    except AttributeError:
+        return None
+
+def __DeviceImpl__get_device_properties(self, ds_class = None):
+    """get_device_properties(self, ds_class = None) -> None
+
+                Utility method that fetches all the device properties from the database
+                and converts them into members of this DeviceImpl.
+
+            Parameters :
+                - ds_class : (DeviceClass) the DeviceClass object. Optional. Default value is
+                             None meaning that the corresponding DeviceClass object for this
+                             DeviceImpl will be used
+
+            Return     : None
+
+            Throws     : DevFailed
+    """
+    if ds_class is None:
+        try:
+            # Call this method in a try/except in case this is called during the DS shutdown sequence
+            ds_class = self.get_device_class()
+        except:
+            return
+    try:
+        self.prop_util = ds_class.prop_util
+        self.device_property_list = copy.deepcopy(ds_class.device_property_list)
+        class_prop = ds_class.class_property_list
+        self.prop_util.get_device_properties(self, class_prop, self.device_property_list)
+        for prop_name in self.device_property_list.keys():
+            setattr(self, prop_name, self.prop_util.get_property_values(prop_name, self.device_property_list))
+    except _PyTango.DevFailed, e:
+        print "----> ", e
+        raise e
+
+def __DeviceImpl__add_attribute(self, attr, r_meth=None, w_meth=None, is_allo_meth=None):
+    """add_attribute(self, attr, r_meth=None, w_meth=None, is_allo_meth=None) -> None
+
+            Add a new attribute to the device attribute list. Please, note that if you add
+            an attribute to a device at device creation time, this attribute will be added
+            to the device class attribute list. Therefore, all devices belonging to the
+            same class created after this attribute addition will also have this attribute.
+
+        Parameters :
+            attr : (Attr) the new attribute to be added to the list.
+            r_meth : (callable) the read method to be called on a read request
+            w_meth : (callable) th write method to be called on a write request (if attr is writable)
+            is_allo_meth: (callable) the method that is called to check if it is possible to access
+                          the attribute or not
+
+        Return     : None
+
+        Throws     : DevFailed"""
+    att_name = attr.get_name()
+
+    add_name_in_list = False
+    if r_meth is not None:
+        r_meth_name = 'read_%s' % att_name
+        if not hasattr(self.__class__, r_meth_name):
+            setattr(self.__class__, r_meth_name, r_meth)
+            add_name_in_list = True
+
+    if w_meth is not None:
+        w_meth_name = 'write_%s' % att_name
+        if not hasattr(self.__class__, w_meth_name):
+            setattr(self.__class__, w_meth_name, w_meth)
+            add_name_in_list = True
+
+    if is_allo_meth is not None:
+        allo_meth_name = 'is_%s_allowed' % att_name
+        if not hasattr(self.__class__, allo_meth_name):
+            setattr(self.__class__, allo_meth_name,is_allo_meth)
+            add_name_in_list = True
+
+    try:
+        self._add_attribute(attr)
+        if add_name_in_list:
+            cl = self.get_device_class()
+            cl.dyn_att_added_methods.append(att_name)
+    except:
+        if add_name_in_list:
+            self._remove_attr_meth(att_name)
+
+def __DeviceImpl__remove_attribute(self, attr_name):
+    """
+        remove_attribute(self, attr_name) -> None
+
+            Remove one attribute from the device attribute list.
+
+        Parameters :
+            - attr_name : (str) attribute name
+
+        Return     : None
+
+        Throws     : DevFailed"""
+    try:
+        # Call this method in a try/except in case remove_attribute
+        # is called during the DS shutdown sequence
+        cl = self.get_device_class()
+    except:
+        return
+
+    dev_list = cl.get_device_list()
+    nb_dev = len(dev_list)
+    if nb_dev == 1:
+        self._remove_attr_meth(attr_name)
+    else:
+        nb_except = 0
+        for dev in dev_list:
+            try:
+                dev.get_device_attr().get_attr_by_name(attr_name)
+            except:
+                nb_except =+ 1
+        if nb_except == nb_dev - 1:
+            self._remove_attr_meth(attr_name)
+    self._remove_attribute(attr_name)
+
+def __DeviceImpl___remove_attr_meth(self,attr_name):
+    """for internal usage only"""
+    cl = self.get_device_class()
+    if cl.dyn_att_added_methods.count(attr_name) != 0:
+        r_meth_name = 'read_%s' % attr_name
+        if hasattr(self.__class__, r_meth_name):
+            delattr(self.__class__, r_meth_name)
+
+    w_meth_name = 'write_%s' % attr_name
+    if hasattr(self.__class__, w_meth_name):
+        delattr(self.__class__, w_meth_name)
+
+    allo_meth_name = 'is_%s_allowed' % attr_name
+    if hasattr(self.__class__, allo_meth_name):
+        delattr(self.__class__, allo_meth_name)
+    cl.dyn_att_added_methods.remove(attr_name)
+
+def __join_msg(msg):
+    return ' '.join(map(str, msg))
+
+def __DeviceImpl__debug_stream(self, *msg):
+    """
+    debug_stream(self, *msg) -> None
+
+            Sends the given message to the tango debug stream.
+
+            Since PyTango 7.1.3, the same can be achieved with::
+            
+                print >>self.log_debug, msg
+            
+        Parameters :
+            - msg : (str) the message to be sent to the debug stream
+        Return     : None
+    """
+    self.__debug_stream(__join_msg(msg))
+
+def __DeviceImpl__info_stream(self, *msg):
+    """
+    info_stream(self, *msg) -> None
+
+            Sends the given message to the tango info stream.
+
+            Since PyTango 7.1.3, the same can be achieved with::
+            
+                print >>self.log_info, msg
+
+        Parameters :
+            - msg : (str) the message to be sent to the info stream
+        Return     : None
+    """
+    self.__info_stream(__join_msg(msg))
+    
+def __DeviceImpl__warn_stream(self, *msg):
+    """
+    warn_stream(self, *msg) -> None
+
+            Sends the given message to the tango warn stream.
+
+            Since PyTango 7.1.3, the same can be achieved with::
+            
+                print >>self.log_warn, msg
+
+        Parameters :
+            - msg : (str) the message to be sent to the warn stream
+        Return     : None
+    """
+    self.__warn_stream(__join_msg(msg))
+    
+def __DeviceImpl__error_stream(self, *msg):
+    """
+    error_stream(self, *msg) -> None
+
+            Sends the given message to the tango error stream.
+
+            Since PyTango 7.1.3, the same can be achieved with::
+            
+                print >>self.log_error, msg
+
+        Parameters :
+            - msg : (str) the message to be sent to the error stream
+        Return     : None
+    """
+    self.__error_stream(__join_msg(msg))
+    
+def __DeviceImpl__fatal_stream(self, *msg):
+    """
+    fatal_stream(self, *msg) -> None
+
+            Sends the given message to the tango fatal stream.
+
+            Since PyTango 7.1.3, the same can be achieved with::
+            
+                print >>self.log_fatal, msg
+
+        Parameters :
+            - msg : (str) the message to be sent to the fatal stream
+        Return     : None
+    """
+    self.__fatal_stream(__join_msg(msg))
+
+ at property
+def __DeviceImpl__debug(self):
+    if not hasattr(self, "_debug_s"):
+        self._debug_s = log4tango.TangoStream(self.debug_stream)
+    return self._debug_s
+
+ at property
+def __DeviceImpl__info(self):
+    if not hasattr(self, "_info_s"):
+        self._info_s = log4tango.TangoStream(self.info_stream)
+    return self._info_s
+
+ at property
+def __DeviceImpl__warn(self):
+    if not hasattr(self, "_warn_s"):
+        self._warn_s = log4tango.TangoStream(self.warn_stream)
+    return self._warn_s
+
+ at property
+def __DeviceImpl__error(self):
+    if not hasattr(self, "_error_s"):
+        self._error_s = log4tango.TangoStream(self.error_stream)
+    return self._error_s
+
+ at property
+def __DeviceImpl__fatal(self):
+    if not hasattr(self, "_fatal_s"):
+        self._fatal_s = log4tango.TangoStream(self.fatal_stream)
+    return self._fatal_s
+
+def __DeviceImpl__str(self):
+    return '%s(%s)' % (self.__class__.__name__, self.get_name())
+
+def __init_DeviceImpl():
+    DeviceImpl._device_class_instance = None
+    DeviceImpl.get_device_class = __DeviceImpl__get_device_class
+    DeviceImpl.get_device_properties = __DeviceImpl__get_device_properties
+    DeviceImpl.add_attribute = __DeviceImpl__add_attribute
+    DeviceImpl.remove_attribute = __DeviceImpl__remove_attribute
+    DeviceImpl._remove_attr_meth = __DeviceImpl___remove_attr_meth
+    DeviceImpl.__str__ = __DeviceImpl__str
+    DeviceImpl.__repr__ = __DeviceImpl__str
+    DeviceImpl.debug_stream = __DeviceImpl__debug_stream
+    DeviceImpl.info_stream = __DeviceImpl__info_stream
+    DeviceImpl.warn_stream = __DeviceImpl__warn_stream
+    DeviceImpl.error_stream = __DeviceImpl__error_stream
+    DeviceImpl.fatal_stream = __DeviceImpl__fatal_stream
+    DeviceImpl.log_debug = __DeviceImpl__debug
+    DeviceImpl.log_info = __DeviceImpl__info
+    DeviceImpl.log_warn = __DeviceImpl__warn
+    DeviceImpl.log_error = __DeviceImpl__error
+    DeviceImpl.log_fatal = __DeviceImpl__fatal
+
+def __Logger__log(self, level, *msg):
+    """
+    log(self, level, *msg) -> None
+
+            Sends the given message to the tango the selected stream.
+
+        Parameters :
+            - level: (Level.LevelLevel) Log level
+            - msg : (str) the message to be sent to the stream
+        Return     : None
+    """
+    self.__log(level, __join_msg(msg))
+
+def __Logger__log_unconditionally(self, level, *msg):
+    """
+    log_unconditionally(self, level, *msg) -> None
+
+            Sends the given message to the tango the selected stream,
+            without checking the level.
+
+        Parameters :
+            - level: (Level.LevelLevel) Log level
+            - msg : (str) the message to be sent to the stream
+        Return     : None
+    """
+    self.__log_unconditionally(level, __join_msg(msg))
+
+def __Logger__debug(self, *msg):
+    """
+    debug(self, *msg) -> None
+
+            Sends the given message to the tango debug stream.
+
+        Parameters :
+            - msg : (str) the message to be sent to the debug stream
+        Return     : None
+    """
+    self.__debug(__join_msg(msg))
+
+def __Logger__info(self, *msg):
+    """
+    info(self, *msg) -> None
+
+            Sends the given message to the tango info stream.
+
+        Parameters :
+            - msg : (str) the message to be sent to the info stream
+        Return     : None
+    """
+    self.__info(__join_msg(msg))
+
+def __Logger__warn(self, *msg):
+    """
+    warn(self, *msg) -> None
+
+            Sends the given message to the tango warn stream.
+
+        Parameters :
+            - msg : (str) the message to be sent to the warn stream
+        Return     : None
+    """
+    self.__warn(__join_msg(msg))
+
+def __Logger__error(self, *msg):
+    """
+    error(self, *msg) -> None
+
+            Sends the given message to the tango error stream.
+
+        Parameters :
+            - msg : (str) the message to be sent to the error stream
+        Return     : None
+    """
+    self.__error(__join_msg(msg))
+
+def __Logger__fatal(self, *msg):
+    """
+    fatal(self, *msg) -> None
+
+            Sends the given message to the tango fatal stream.
+
+        Parameters :
+            - msg : (str) the message to be sent to the fatal stream
+        Return     : None
+    """
+    self.__fatal(__join_msg(msg))
+
+def __Attr__str(self):
+    return '%s(%s)' % (self.__class__.__name__, self.get_name())
+
+def __init_Attr():
+    Attr.__str__ = __Attr__str
+    Attr.__repr__ = __Attr__str
+
+def __Attribute__str(self):
+    return '%s(%s)' % (self.__class__.__name__, self.get_name())
+
+def __init_Attribute():
+    Attribute.__str__ = __Attribute__str
+    Attribute.__repr__ = __Attribute__str
+
+def __init_Logger():
+    Logger.log = __Logger__log
+    Logger.log_unconditionally = __Logger__log_unconditionally
+    Logger.debug = __Logger__debug
+    Logger.info = __Logger__info
+    Logger.warn = __Logger__warn
+    Logger.error = __Logger__error
+    Logger.fatal = __Logger__fatal
+
+def __doc_DeviceImpl():
+    def document_method(method_name, desc, append=True):
+        return __document_method(DeviceImpl, method_name, desc, append)
+
+    DeviceImpl.__doc__ = """
+    Base class for all TANGO device.
+    This class inherits from CORBA classes where all the network layer is implemented.
+    """
+
+    document_method("init_device", """
+    init_device(self) -> None
+
+            Intialise a device.
+
+        Parameters : None
+        Return     : None
+
+    """ )
+
+    document_method("set_state", """
+    set_state(self, new_state) -> None
+
+            Set device state.
+
+        Parameters :
+            - new_state : (DevState) the new device state
+        Return     : None
+
+    """ )
+
+    document_method("get_state", """
+    get_state(self) -> DevState
+
+            Get a COPY of the device state.
+
+        Parameters : None
+        Return     : (DevState) Current device state
+
+    """ )
+
+    document_method("get_prev_state", """
+    get_prev_state(self) -> DevState
+
+            Get a COPY of the device's previous state.
+
+        Parameters : None
+        Return     : (DevState) the device's previous state
+
+    """ )
+
+    document_method("get_name", """
+    get_name(self) -> (str)
+
+            Get a COPY of the device name.
+
+        Parameters : None
+        Return     : (str) the device name
+
+    """ )
+
+    document_method("get_device_attr", """
+    get_device_attr(self) -> MultiAttribute
+
+            Get device multi attribute object.
+
+        Parameters : None
+        Return     : (MultiAttribute) the device's MultiAttribute object
+
+    """ )
+
+    document_method("register_signal", """
+    register_signal(self, signo) -> None
+
+            Register a signal.
+            Register this device as device to be informed when signal signo
+            is sent to to the device server process
+
+        Parameters :
+            - signo : (int) signal identifier
+        Return     : None
+
+    """ )
+
+    document_method("unregister_signal", """
+    unregister_signal(self, signo) -> None
+
+            Unregister a signal.
+            Unregister this device as device to be informed when signal signo
+            is sent to to the device server process
+
+        Parameters :
+            - signo : (int) signal identifier
+        Return     : None
+
+    """ )
+
+    document_method("get_status", """
+    get_status(self, ) -> str
+
+            Get a COPY of the device status.
+
+        Parameters : None
+        Return     : (str) the device status
+
+    """ )
+
+    document_method("set_status", """
+    set_status(self, new_status) -> None
+
+            Set device status.
+
+        Parameters :
+            - new_status : (str) the new device status
+        Return     : None
+
+    """ )
+
+    document_method("append_status", """
+    append_status(self, status, new_line=False) -> None
+
+            Appends a string to the device status.
+
+        Parameters :
+            status : (str) the string to be appened to the device status
+            new_line : (bool) If true, appends a new line character before the string. Default is False
+        Return     : None
+
+    """ )
+
+    document_method("dev_state", """
+    dev_state(self) -> DevState
+
+            Get device state.
+            Default method to get device state. The behaviour of this method depends
+            on the device state. If the device state is ON or ALARM, it reads the
+            attribute(s) with an alarm level defined, check if the read value is
+            above/below the alarm and eventually change the state to ALARM, return
+            the device state. For all th other device state, this method simply
+            returns the state This method can be redefined in sub-classes in case
+            of the default behaviour does not fullfill the needs.
+
+        Parameters : None
+        Return     : (DevState) the device state
+
+        Throws     : DevFailed - If it is necessary to read attribute(s) and a problem occurs during the reading
+    """ )
+
+    document_method("dev_status", """
+    dev_status(self) -> str
+
+            Get device status.
+            Default method to get device status. It returns the contents of the device
+            dev_status field. If the device state is ALARM, alarm messages are added
+            to the device status. This method can be redefined in sub-classes in case
+            of the default behaviour does not fullfill the needs.
+
+        Parameters : None
+        Return     : (str) the device status
+
+        Throws     : DevFailed - If it is necessary to read attribute(s) and a problem occurs during the reading
+    """ )
+
+    document_method("set_change_event", """
+    set_change_event(self, attr_name, implemented, detect=True) -> None
+
+            Set an implemented flag for the attribute to indicate that the server fires
+            change events manually, without the polling to be started.
+            If the detect parameter is set to true, the criteria specified for the
+            change event are verified and the event is only pushed if they are fullfilled.
+            If detect is set to false the event is fired without any value checking!
+
+        Parameters :
+            - attr_name : (str) attribute name
+            - implemented : (bool) True when the server fires change events manually.
+            - detect : (bool) Triggers the verification of the change event properties
+                       when set to true. Default value is true.
+        Return     : None
+    """ )
+
+    document_method("set_archive_event", """
+    set_archive_event(self, attr_name, implemented, detect=True) -> None
+
+            Set an implemented flag for the attribute to indicate that the server fires
+            archive events manually, without the polling to be started.
+            If the detect parameter is set to true, the criteria specified for the
+            archive event are verified and the event is only pushed if they are fullfilled.
+            If detect is set to false the event is fired without any value checking!
+
+        Parameters :
+            - attr_name : (str) attribute name
+            - implemented : (bool) True when the server fires change events manually.
+            - detect : (bool) Triggers the verification of the change event properties
+                       when set to true. Default value is true.
+        Return     : None
+
+    """ )
+
+    document_method("push_change_event", """
+    push_change_event(self, attr_name) -> None
+    push_change_event(self, attr_name, except) -> None
+    push_change_event(self, attr_name, data, dim_x = 1, dim_y = 0) -> None
+    push_change_event(self, attr_name, str_data, data) -> None
+    push_change_event(self, attr_name, data, time_stamp, quality, dim_x = 1, dim_y = 0) -> None
+    push_change_event(self, attr_name, str_data, data, time_stamp, quality) -> None
+
+        Push a change event for the given attribute name.
+        The event is pushed to the notification daemon.
+
+        Parameters:
+            - attr_name : (str) attribute name
+            - data : the data to be sent as attribute event data. Data must be compatible with the
+                     attribute type and format.
+                     for SPECTRUM and IMAGE attributes, data can be any type of sequence of elements
+                     compatible with the attribute type
+            - str_data : (str) special variation for DevEncoded data type. In this case 'data' must also
+                         be a str.
+            - except: (DevFailed) Instead of data, you may want to send an exception.
+            - dim_x : (int) the attribute x length. Default value is 1
+            - dim_y : (int) the attribute y length. Default value is 0
+            - time_stamp : (double) the time stamp
+            - quality : (AttrQuality) the attribute quality factor
+
+        Throws     : DevFailed If the attribute data type is not coherent.
+    """ )
+
+    document_method("push_archive_event", """
+    push_archive_event(self, attr_name) -> None
+    push_archive_event(self, attr_name, except) -> None
+    push_archive_event(self, attr_name, data, dim_x = 1, dim_y = 0) -> None
+    push_archive_event(self, attr_name, str_data, data) -> None
+    push_archive_event(self, attr_name, data, time_stamp, quality, dim_x = 1, dim_y = 0) -> None
+    push_archive_event(self, attr_name, str_data, data, time_stamp, quality) -> None
+
+            Push an archive event for the given attribute name.
+            The event is pushed to the notification daemon.
+
+        Parameters:
+            - attr_name : (str) attribute name
+            - data : the data to be sent as attribute event data. Data must be compatible with the
+                     attribute type and format.
+                     for SPECTRUM and IMAGE attributes, data can be any type of sequence of elements
+                     compatible with the attribute type
+            - str_data : (str) special variation for DevEncoded data type. In this case 'data' must also
+                         be a str.
+            - except: (DevFailed) Instead of data, you may want to send an exception.
+            - dim_x : (int) the attribute x length. Default value is 1
+            - dim_y : (int) the attribute y length. Default value is 0
+            - time_stamp : (double) the time stamp
+            - quality : (AttrQuality) the attribute quality factor
+
+        Throws     : DevFailed If the attribute data type is not coherent.
+    """ )
+
+    document_method("push_event", """
+    push_event(self, attr_name, filt_names, filt_vals) -> None
+    push_event(self, attr_name, filt_names, filt_vals, data, dim_x = 1, dim_y = 0) -> None
+    push_event(self, attr_name, filt_names, filt_vals, str_data, data) -> None
+    push_event(self, attr_name, filt_names, filt_vals, data, time_stamp, quality, dim_x = 1, dim_y = 0) -> None
+    push_event(self, attr_name, filt_names, filt_vals, str_data, data, time_stamp, quality) -> None
+
+            Push a user event for the given attribute name.
+            The event is pushed to the notification daemon.
+
+        Parameters:
+            - attr_name : (str) attribute name
+            - filt_names : (sequence<str>) the filterable fields name
+            - filt_vals : (sequence<double>) the filterable fields value
+            - data : the data to be sent as attribute event data. Data must be compatible with the
+                     attribute type and format.
+                     for SPECTRUM and IMAGE attributes, data can be any type of sequence of elements
+                     compatible with the attribute type
+            - str_data : (str) special variation for DevEncoded data type. In this case 'data' must also
+                         be a str.
+            - dim_x : (int) the attribute x length. Default value is 1
+            - dim_y : (int) the attribute y length. Default value is 0
+            - time_stamp : (double) the time stamp
+            - quality : (AttrQuality) the attribute quality factor
+
+        Throws     : DevFailed If the attribute data type is not coherent.
+    """ )
+
+    document_method("push_data_ready_event", """
+    push_data_ready_event(self, attr_name, counter = 0) -> None
+
+            Push a data ready event for the given attribute name.
+            The event is pushed to the notification daemon.
+
+            The method needs only the attribue name and an optional
+            "counter" which will be passed unchanged within the event
+
+        Parameters :
+            - attr_name : (str) attribute name
+            - counter : (int) the user counter
+        Return     : None
+
+        Throws     : DevFailed If the attribute name is unknown.
+    """ )
+
+    document_method("get_logger", """
+    get_logger(self) -> Logger
+
+            Returns the Logger object for this device
+
+        Parameters : None
+        Return     : (Logger) the Logger object for this device
+    """ )
+
+    document_method("get_exported_flag", """
+    get_exported_flag(self) -> bool
+
+            Returns the state of the exported flag
+
+        Parameters : None
+        Return     : (bool) the state of the exported flag
+        
+        New in PyTango 7.1.2
+    """ )
+    
+    document_method("get_poll_ring_depth", """
+    get_poll_ring_depth(self) -> int
+
+            Returns the poll ring depth
+
+        Parameters : None
+        Return     : (int) the poll ring depth
+        
+        New in PyTango 7.1.2
+    """ )
+
+    document_method("get_poll_old_factor", """
+    get_poll_old_factor(self) -> int
+
+            Returns the poll old factor
+
+        Parameters : None
+        Return     : (int) the poll old factor
+        
+        New in PyTango 7.1.2
+    """ )
+    
+    document_method("is_polled", """
+    is_polled(self) -> bool
+
+            Returns if it is polled
+
+        Parameters : None
+        Return     : (bool) True if it is polled or False otherwise
+        
+        New in PyTango 7.1.2
+    """ )
+
+    document_method("get_polled_cmd", """
+    get_polled_cmd(self) -> sequence<str>
+
+            Returns a COPY of the list of polled commands
+
+        Parameters : None
+        Return     : (sequence<str>) a COPY of the list of polled commands
+        
+        New in PyTango 7.1.2
+    """ )
+    
+    document_method("get_polled_attr", """
+    get_polled_attr(self) -> sequence<str>
+
+            Returns a COPY of the list of polled attributes
+
+        Parameters : None
+        Return     : (sequence<str>) a COPY of the list of polled attributes
+        
+        New in PyTango 7.1.2
+    """ )
+    
+    document_method("get_non_auto_polled_cmd", """
+    get_non_auto_polled_cmd(self) -> sequence<str>
+
+            Returns a COPY of the list of non automatic polled commands
+
+        Parameters : None
+        Return     : (sequence<str>) a COPY of the list of non automatic polled commands
+        
+        New in PyTango 7.1.2
+    """ )
+    
+    document_method("get_non_auto_polled_attr", """
+    get_non_auto_polled_attr(self) -> sequence<str>
+
+            Returns a COPY of the list of non automatic polled attributes
+
+        Parameters : None
+        Return     : (sequence<str>) a COPY of the list of non automatic polled attributes
+        
+        New in PyTango 7.1.2
+    """ )
+
+    document_method("stop_polling", """
+    stop_polling(self) -> None
+    stop_polling(self, with_db_upd) -> None
+            
+            Stop all polling for a device. if the device is polled, call this
+            method before deleting it.
+
+        Parameters :
+            - with_db_upd : (bool)  Is it necessary to update db ?
+        Return     : None
+        
+        New in PyTango 7.1.2
+    """ )
+
+    document_method("check_command_exists", """
+    check_command_exists(self) -> None
+
+            This method check that a command is supported by the device and
+            does not need input value. The method throws an exception if the
+            command is not defined or needs an input value
+
+        Parameters :
+            - cmd_name: (str) the command name
+        Return     : None
+        
+        Throws     : DevFailed API_IncompatibleCmdArgumentType, API_CommandNotFound 
+        
+        New in PyTango 7.1.2
+    """ )
+    
+    document_method("get_dev_idl_version", """
+    get_dev_idl_version(self) -> int
+
+            Returns the IDL version
+
+        Parameters : None
+        Return     : (int) the IDL version
+        
+        New in PyTango 7.1.2
+    """ )
+    
+    document_method("get_cmd_poll_ring_depth", """
+    get_cmd_poll_ring_depth(self, cmd_name) -> int
+
+            Returns the command poll ring depth
+
+        Parameters :
+            - cmd_name: (str) the command name
+        Return     : (int) the command poll ring depth
+        
+        New in PyTango 7.1.2
+    """ )
+
+    document_method("get_attr_poll_ring_depth", """
+    get_attr_poll_ring_depth(self, attr_name) -> int
+
+            Returns the attribute poll ring depth
+
+        Parameters :
+            - attr_name: (str) the attribute name
+        Return     : (int) the attribute poll ring depth
+        
+        New in PyTango 7.1.2
+    """ )
+
+    document_method("is_device_locked", """
+    is_device_locked(self) -> bool
+
+            Returns if this device is locked by a client
+
+        Parameters : None
+        Return     : (bool) True if it is locked or False otherwise
+        
+        New in PyTango 7.1.2
+    """ )
+    
+def __doc_extra_DeviceImpl(cls):
+    def document_method(method_name, desc, append=True):
+        return __document_method(cls, method_name, desc, append)
+
+    document_method("always_executed_hook", """
+    always_executed_hook(self) -> None
+
+            Hook method.
+            Default method to implement an action necessary on a device before
+            any command is executed. This method can be redefined in sub-classes
+            in case of the default behaviour does not fullfill the needs
+
+        Parameters : None
+        Return     : None
+
+        Throws     : DevFailed This method does not throw exception but a redefined method can.
+    """ )
+
+    document_method("read_attr_hardware", """
+    read_attr_hardware(self, attr_list) -> None
+
+            Read the hardware to return attribute value(s).
+            Default method to implement an action necessary on a device to read
+            the hardware involved in a a read attribute CORBA call. This method
+            must be redefined in sub-classes in order to support attribute reading
+
+        Parameters :
+            attr_list : (sequence<int>) list of indices in the device object attribute vector
+                        of an attribute to be read.
+        Return     : None
+
+        Throws     : DevFailed This method does not throw exception but a redefined method can.
+    """ )
+
+    document_method("write_attr_hardware", """
+    write_attr_hardware(self) -> None
+
+            Write the hardware for attributes.
+            Default method to implement an action necessary on a device to write
+            the hardware involved in a a write attribute. This method must be
+             redefined in sub-classes in order to support writable attribute
+
+        Parameters :
+            attr_list : (sequence<int>) list of indices in the device object attribute vector
+                        of an attribute to be written.
+        Return     : None
+
+        Throws     : DevFailed This method does not throw exception but a redefined method can.
+    """ )
+
+    document_method("signal_handler", """
+    signal_handler(self, signo) -> None
+
+            Signal handler.
+            The method executed when the signal arrived in the device server process.
+            This method is defined as virtual and then, can be redefined following
+            device needs.
+
+        Parameters :
+            - signo : (int) the signal number
+        Return     : None
+
+        Throws     : DevFailed This method does not throw exception but a redefined method can.
+    """ )
+
+    copy_doc(cls, "dev_state")
+    copy_doc(cls, "dev_status")
+
+def __doc_Attribute():
+    def document_method(method_name, desc, append=True):
+        return __document_method(Attribute, method_name, desc, append)
+
+    Attribute.__doc__ = """
+    This class represents a Tango attribute.
+    """
+
+    document_method("is_write_associated", """
+    is_write_associated(self) -> bool
+
+            Check if the attribute has an associated writable attribute.
+
+        Parameters : None
+        Return     : (bool) True if there is an associated writable attribute
+    """ )
+
+    document_method("is_min_alarm", """
+    is_min_alarm(self) -> bool
+
+            Check if the attribute is in minimum alarm condition.
+
+        Parameters : None
+        Return     : (bool) true if the attribute is in alarm condition (read value below the min. alarm).
+    """ )
+
+    document_method("is_max_alarm", """
+    is_max_alarm(self) -> bool
+
+            Check if the attribute is in maximum alarm condition.
+
+        Parameters : None
+        Return     : (bool) true if the attribute is in alarm condition (read value above the max. alarm).
+    """ )
+
+    document_method("is_min_warning", """
+    is_min_warning(self) -> bool
+
+            Check if the attribute is in minimum warning condition.
+
+        Parameters : None
+        Return     : (bool) true if the attribute is in warning condition (read value below the min. warning).
+    """ )
+
+    document_method("is_max_warning", """
+    is_max_warning(self) -> bool
+
+            Check if the attribute is in maximum warning condition.
+
+        Parameters : None
+        Return     : (bool) true if the attribute is in warning condition (read value above the max. warning).
+    """ )
+
+    document_method("is_rds_alarm", """
+    is_rds_alarmself) -> bool
+
+            Check if the attribute is in RDS alarm condition.
+
+        Parameters : None
+        Return     : (bool) true if the attribute is in RDS condition (Read Different than Set).
+    """ )
+
+    document_method("is_polled", """
+    is_polled(self) -> bool
+
+            Check if the attribute is polled.
+
+        Parameters : None
+        Return     : (bool) true if the attribute is polled.
+    """ )
+
+    document_method("check_alarm", """
+    check_alarm(self) -> bool
+
+            Check if the attribute read value is below/above the alarm level.
+
+        Parameters : None
+        Return     : (bool) true if the attribute is in alarm condition.
+
+        Throws     : DevFailed If no alarm level is defined.
+    """ )
+
+    document_method("get_writable", """
+    get_writable(self) -> AttrWriteType
+
+            Get the attribute writable type (RO/WO/RW).
+
+        Parameters : None
+        Return     : (AttrWriteType) The attribute write type.
+    """ )
+
+    document_method("get_name", """
+    get_name(self) -> str
+
+            Get attribute name.
+
+        Parameters : None
+        Return     : (str) The attribute name
+    """ )
+
+    document_method("get_data_type", """
+    get_data_type(self) -> int
+
+            Get attribute data type.
+
+        Parameters : None
+        Return     : (int) the attribute data type
+    """ )
+
+    document_method("get_data_format", """
+    get_data_format(self) -> AttrDataFormat
+
+            Get attribute data format.
+
+        Parameters : None
+        Return     : (AttrDataFormat) the attribute data format
+    """ )
+
+    document_method("get_assoc_name", """
+    get_assoc_name(self) -> str
+
+            Get name of the associated writable attribute.
+
+        Parameters : None
+        Return     : (str) the associated writable attribute name
+    """ )
+
+    document_method("get_assoc_ind", """
+    get_assoc_ind(self) -> int
+
+            Get index of the associated writable attribute.
+
+        Parameters : None
+        Return     : (int) the index in the main attribute vector of the associated writable attribute
+    """ )
+
+    document_method("set_assoc_ind", """
+    set_assoc_ind(self, index) -> None
+
+            Set index of the associated writable attribute.
+
+        Parameters :
+            - index : (int) The new index in the main attribute vector of the associated writable attribute
+        Return     : None
+    """ )
+
+    document_method("get_date", """
+    get_date(self) -> TimeVal
+
+            Get a COPY of the attribute date.
+
+        Parameters : None
+        Return     : (TimeVal) the attribute date
+    """ )
+
+    document_method("set_date", """
+    set_date(self, new_date) -> None
+
+            Set attribute date.
+
+        Parameters :
+            - new_date : (TimeVal) the attribute date
+        Return     : None
+    """ )
+
+    document_method("get_label", """
+    get_label(self, ) -> str
+
+            Get attribute label property.
+
+        Parameters : None
+        Return     : (str) he attribute label
+    """ )
+
+    document_method("get_quality", """
+    get_quality(self) -> AttrQuality
+
+            Get a COPY of the attribute data quality.
+
+        Parameters : None
+        Return     : (AttrQuality) the attribute data quality
+    """ )
+
+    document_method("set_quality", """
+    set_quality(self, quality, send_event=False) -> None
+
+            Set attribute data quality.
+
+        Parameters :
+            - quality : (AttrQuality) the new attribute data quality
+            - send_event : (bool) true if a change event should be sent. Default is false.
+        Return     : None
+    """ )
+
+    document_method("get_data_size", """
+    get_data_size(self) -> None
+
+            Get attribute data size.
+
+        Parameters : None
+        Return     : (int) the attribute data size
+    """ )
+
+    document_method("get_x", """
+    get_x(self) -> int
+
+            Get attribute data size in x dimension.
+
+        Parameters : None
+        Return     : (int) the attribute data size in x dimension. Set to 1 for scalar attribute
+    """ )
+
+    document_method("get_max_dim_x", """
+    get_max_dim_x(self) -> int
+
+            Get attribute maximum data size in x dimension.
+
+        Parameters : None
+        Return     : (int) the attribute maximum data size in x dimension. Set to 1 for scalar attribute
+    """ )
+
+    document_method("get_y", """
+    get_y(self) -> int
+
+            Get attribute data size in y dimension.
+
+        Parameters : None
+        Return     : (int) the attribute data size in y dimension. Set to 1 for scalar attribute
+    """ )
+
+    document_method("get_max_dim_y", """
+    get_max_dim_y(self) -> int
+
+            Get attribute maximum data size in y dimension.
+
+        Parameters : None
+        Return     : (int) the attribute maximum data size in y dimension. Set to 0 for scalar attribute
+    """ )
+
+    document_method("get_polling_period", """
+    get_polling_period(self) -> int
+
+            Get attribute polling period.
+
+        Parameters : None
+        Return     : (int) The attribute polling period in mS. Set to 0 when the attribute is not polled
+    """ )
+
+    document_method("set_attr_serial_model", """
+    set_attr_serial_model(self, ser_model) -> void
+
+            Set attribute serialization model.
+            This method allows the user to choose the attribute serialization model.
+
+        Parameters :
+            - ser_model : (AttrSerialModel) The new serialisation model. The 
+                          serialization model must be one of ATTR_BY_KERNEL, 
+                          ATTR_BY_USER or ATTR_NO_SYNC
+        Return     : None
+        
+        New in PyTango 7.1.0
+    """ )
+
+    document_method("get_attr_serial_model", """
+    get_attr_serial_model(self) -> AttrSerialModel
+
+            Get attribute serialization model.
+
+        Parameters : None
+        Return     : (AttrSerialModel) The attribute serialization model 
+        
+        New in PyTango 7.1.0
+    """ )
+    
+    document_method("set_value", """
+    set_value(self, data, dim_x = 1, dim_y = 0) -> None <= DEPRECATED
+    set_value(self, data)
+    set_value(self, str_data, data) -> None
+
+            Set internal attribute value.
+            This method stores the attribute read value inside the object.
+            This method also stores the date when it is called and initializes the attribute quality factor.
+        Parameters :
+            - data : the data to be set. Data must be compatible with the attribute type and format.
+                     In the DEPRECATED form for SPECTRUM and IMAGE attributes, data
+                     can be any type of FLAT sequence of elements compatible with the
+                     attribute type.
+                     In the new form (without dim_x or dim_y) data should be any
+                     sequence for SPECTRUM and a SEQUENCE of equal-lenght SEQUENCES
+                     for IMAGE attributes.
+                     The recommended sequence is a C continuous and aligned numpy
+                     array, as it can be optimized.
+            - str_data : (str) special variation for DevEncoded data type. In this case 'data' must also
+                         be a str.
+            - dim_x : (int) [DEPRECATED] the attribute x length. Default value is 1
+            - dim_y : (int) [DEPRECATED] the attribute y length. Default value is 0
+        Return     : None
+    """ )
+
+    document_method("set_value_date_quality", """
+    set_value_date_quality(self, data, time_stamp, quality, dim_x = 1, dim_y = 0) -> None <= DEPRECATED
+    set_value_date_quality(self, data, time_stamp, quality) -> None
+    set_value_date_quality(self, str_data, data, time_stamp, quality) -> None
+
+            Set internal attribute value, date and quality factor.
+            This method stores the attribute read value, the date and the attribute quality
+            factor inside the object.
+
+        Parameters :
+            - data : the data to be set. Data must be compatible with the attribute type and format.
+                     In the DEPRECATED form for SPECTRUM and IMAGE attributes, data
+                     can be any type of FLAT sequence of elements compatible with the
+                     attribute type.
+                     In the new form (without dim_x or dim_y) data should be any
+                     sequence for SPECTRUM and a SEQUENCE of equal-lenght SEQUENCES
+                     for IMAGE attributes.
+                     The recommended sequence is a C continuous and aligned numpy
+                     array, as it can be optimized.
+            - str_data : (str) special variation for DevEncoded data type. In this case 'data' must also
+                         be a str.
+            - dim_x : (int) [DEPRECATED] the attribute x length. Default value is 1
+            - dim_y : (int) [DEPRECATED] the attribute y length. Default value is 0
+            - time_stamp : (double) the time stamp
+            - quality : (AttrQuality) the attribute quality factor
+        Return     : None
+    """ )
+
+    document_method("set_change_event", """
+    set_change_event(self, implemented, detect = True) -> None
+
+            Set a flag to indicate that the server fires change events manually, 
+            without the polling to be started for the attribute. 
+            If the detect parameter is set to true, the criteria specified for 
+            the change event are verified and the event is only pushed if they 
+            are fullfilled. If detect is set to false the event is fired without 
+            any value checking!
+
+        Parameters :
+            - implemented : (bool) True when the server fires change events manually. 
+            - detect : (bool) (optional, default is True) Triggers the verification of 
+                       the change event properties when set to true. 
+        Return     : None
+        
+        New in PyTango 7.1.0
+    """ )
+
+    document_method("set_archive_event", """
+    set_archive_event(self, implemented, detect = True) -> None
+
+            Set a flag to indicate that the server fires archive events manually, 
+            without the polling to be started for the attribute If the detect parameter 
+            is set to true, the criteria specified for the archive event are verified 
+            and the event is only pushed if they are fullfilled.
+
+        Parameters :
+            - implemented : (bool) True when the server fires archive events manually. 
+            - detect : (bool) (optional, default is True) Triggers the verification of 
+                       the archive event properties when set to true. 
+        Return     : None
+        
+        New in PyTango 7.1.0
+    """ )
+    
+    document_method("is_change_event", """
+    is_change_event(self) -> bool
+
+            Check if the change event is fired manually (without polling) for this attribute. 
+
+        Parameters : None
+        Return     : (bool) True if a manual fire change event is implemented. 
+        
+        New in PyTango 7.1.0
+    """ )
+
+    document_method("is_check_change_criteria", """
+    is_check_change_criteria(self) -> bool
+
+            Check if the change event criteria should be checked when firing the 
+            event manually.
+
+        Parameters : None
+        Return     : (bool) True if a change event criteria will be checked.
+        
+        New in PyTango 7.1.0
+    """ )
+
+    document_method("is_archive_event", """
+    is_archive_event(self) -> bool
+
+            Check if the archive event is fired manually (without polling) for this attribute. 
+
+        Parameters : None
+        Return     : (bool) True if a manual fire archive event is implemented. 
+        
+        New in PyTango 7.1.0
+    """ )
+
+    document_method("is_check_archive_criteria", """
+    is_check_archive_criteria(self) -> bool
+
+            Check if the archive event criteria should be checked when firing the 
+            event manually.
+
+        Parameters : None
+        Return     : (bool) True if a archive event criteria will be checked.
+        
+        New in PyTango 7.1.0
+    """ )
+
+    document_method("remove_configuration", """
+    remove_configuration(self) -> None
+
+            Remove the attribute configuration from the database.
+            This method can be used to clean-up all the configuration of an 
+            attribute to come back to its default values or the remove all 
+            configuration of a dynamic attribute before deleting it.
+
+            The method removes all configured attribute properties and removes
+            the attribute from the list of polled attributes.
+
+        Parameters : None
+        Return     : None
+        
+        New in PyTango 7.1.0
+    """ )
+
+def __doc_WAttribute():
+    def document_method(method_name, desc, append=True):
+        return __document_method(WAttribute, method_name, desc, append)
+
+    WAttribute.__doc__ = """
+    This class represents a Tango writable attribute.
+    """
+
+    document_method("get_min_value", """
+    get_min_value(self) -> obj
+
+            Get attribute minimum value or throws an exception if the
+            attribute does not have a minimum value.
+
+        Parameters : None
+        Return     : (obj) an object with the python minimum value
+    """ )
+
+    document_method("get_max_value", """
+    get_max_value(self) -> obj
+
+            Get attribute maximum value or throws an exception if the
+            attribute does not have a maximum value.
+
+        Parameters : None
+        Return     : (obj) an object with the python maximum value
+    """ )
+
+    document_method("set_min_value", """
+    set_min_value(self, data) -> None
+
+            Set attribute minimum value.
+
+        Parameters :
+            - data : the attribute minimum value. python data type must be compatible
+                     with the attribute data format and type.
+        Return     : None
+    """ )
+
+    document_method("set_max_value", """
+    set_max_value(self, data) -> None
+
+            Set attribute maximum value.
+
+        Parameters :
+            - data : the attribute maximum value. python data type must be compatible
+                     with the attribute data format and type.
+        Return     : None
+    """ )
+
+    document_method("is_min_value", """
+    is_min_value(self) -> bool
+
+            Check if the attribute has a minimum value.
+
+        Parameters : None
+        Return     : (bool) true if the attribute has a minimum value defined
+    """ )
+
+    document_method("is_max_value", """
+    is_max_value(self, ) -> bool
+
+            Check if the attribute has a maximum value.
+
+
+        Parameters : None
+        Return     : (bool) true if the attribute has a maximum value defined
+    """ )
+
+    document_method("get_write_value_length", """
+    get_write_value_length(self) -> int
+
+            Retrieve the new value length (data number) for writable attribute.
+
+        Parameters : None
+        Return     : (int) the new value data length
+    """ )
+
+#    document_method("set_write_value", """
+#    set_write_value(self, data, dim_x = 1, dim_y = 0) -> None
+#
+#            Set the writable attribute value.
+#
+#        Parameters :
+#            - data : the data to be set. Data must be compatible with the attribute type and format.
+#                     for SPECTRUM and IMAGE attributes, data can be any type of sequence of elements
+#                     compatible with the attribute type
+#            - dim_x : (int) the attribute set value x length. Default value is 1
+#            - dim_y : (int) the attribute set value y length. Default value is 0
+#        Return     : None
+#    """ )
+
+    document_method("get_write_value", """
+    get_write_value(self, lst) -> None  <= DEPRECATED
+    get_write_value(self, extract_as=ExtractAs.Numpy) -> obj
+
+            Retrieve the new value for writable attribute.
+
+        Parameters :
+            - extract_as: (ExtractAs)
+            - lst : [out] (list) a list object that will be filled with the attribute write value (DEPRECATED)
+        Return     : (obj) the attribute write value.
+    """ )
+
+def __doc_MultiAttribute():
+    def document_method(method_name, desc, append=True):
+        return __document_method(MultiAttribute, method_name, desc, append)
+
+    MultiAttribute.__doc__ = """
+    There is one instance of this class for each device.
+    This class is mainly an aggregate of Attribute or WAttribute objects. 
+    It eases management of multiple attributes"""
+    
+    document_method("get_attr_by_name", """
+    get_attr_by_name(self, attr_name) -> Attribute
+
+            Get Attribute object from its name.
+            This method returns an Attribute object with a name passed as 
+            parameter. The equality on attribute name is case independant.
+
+        Parameters :
+            - attr_name : (str) attribute name
+        Return     : (Attribute) the attribute object
+        
+        Throws     : DevFailed If the attribute is not defined.
+    """ )
+
+    document_method("get_attr_by_ind", """
+    get_attr_by_ind(self, ind) -> Attribute
+
+            Get Attribute object from its index.
+            This method returns an Attribute object from the index in the 
+            main attribute vector.
+
+        Parameters :
+            - ind : (int) the attribute index
+        Return     : (Attribute) the attribute object
+    """ )
+
+    document_method("get_w_attr_by_name", """
+    get_w_attr_by_name(self, attr_name) -> WAttribute
+
+            Get a writable attribute object from its name.
+            This method returns an WAttribute object with a name passed as 
+            parameter. The equality on attribute name is case independant.
+
+        Parameters :
+            - attr_name : (str) attribute name
+        Return     : (WAttribute) the attribute object
+        
+        Throws     : DevFailed If the attribute is not defined.
+    """ )
+
+    document_method("get_w_attr_by_ind", """
+    get_w_attr_by_ind(self, ind) -> WAttribute
+
+            Get a writable attribute object from its index.
+            This method returns an WAttribute object from the index in the 
+            main attribute vector.
+
+        Parameters :
+            - ind : (int) the attribute index
+        Return     : (WAttribute) the attribute object
+    """ )
+    
+    document_method("get_attr_ind_by_name", """
+    get_attr_ind_by_name(self, attr_name) -> int
+
+            Get Attribute index into the main attribute vector from its name.
+            This method returns the index in the Attribute vector (stored in the 
+            MultiAttribute object) of an attribute with a given name. 
+            The name equality is case independant.
+
+        Parameters :
+            - attr_name : (str) attribute name
+        Return     : (int) the attribute index
+        
+        Throws     : DevFailed If the attribute is not found in the vector.
+        
+        New in PyTango 7.0.0
+    """ )
+    
+    document_method("get_attr_nb", """
+    get_attr_nb(self) -> int
+
+            Get attribute number.
+
+        Parameters : None
+        Return     : (int) the number of attributes
+        
+        New in PyTango 7.0.0
+    """ )
+    
+    document_method("check_alarm", """
+    check_alarm(self) -> bool
+    check_alarm(self, attr_name) -> bool
+    check_alarm(self, ind) -> bool
+            
+            - The 1st version of the method checks alarm on all attribute(s) with an alarm defined.
+            - The 2nd version of the method checks alarm for one attribute with a given name.
+            - The 3rd version of the method checks alarm for one attribute from its index in the main attributes vector.
+            
+        Parameters : 
+            - attr_name : (str) attribute name
+            - ind : (int) the attribute index
+        Return     : (bool) True if at least one attribute is in alarm condition
+        
+        Throws     : DevFailed If at least one attribute does not have any alarm level defined
+
+        New in PyTango 7.0.0
+    """ )
+    
+    document_method("read_alarm", """
+    read_alarm(self, status) -> None
+
+            Add alarm message to device status.
+            This method add alarm mesage to the string passed as parameter. 
+            A message is added for each attribute which is in alarm condition
+
+        Parameters :
+            - status : (str) a string (should be the device status) 
+        Return     : None
+        
+        New in PyTango 7.0.0
+    """ )
+    
+def __doc_Attr():
+    def document_method(method_name, desc, append=True):
+        return __document_method(Attr, method_name, desc, append)
+
+    Attr.__doc__ = """
+    This class represents a Tango writable attribute.
+    """
+
+    document_method("set_default_properties", """
+    set_default_properties(self) -> None
+
+            Set default attribute properties.
+
+        Parameters :
+            - attr_prop : (UserDefaultAttrProp) the user default property class
+        Return     : None
+    """ )
+
+    document_method("set_disp_level", """
+    set_disp_level(self, disp_lelel) -> None
+
+            Set the attribute display level.
+
+        Parameters :
+            - disp_level : (DispLevel) the new display level
+        Return     : None
+    """ )
+
+    document_method("set_polling_period", """
+    set_polling_period(self, period) -> None
+
+            Set the attribute polling update period.
+
+        Parameters :
+            - period : (int) the attribute polling period (in mS)
+        Return     : None
+    """ )
+
+    document_method("set_memorized", """
+    set_memorized(self) -> None
+
+            Set the attribute as memorized in database (only for scalar
+            and writable attribute) With no argument the setpoint will be
+            written to the attribute during initialisation!
+
+        Parameters : None
+        Return     : None
+    """ )
+
+    document_method("set_memorized_init", """
+    set_memorized_init(self, write_on_init) -> None
+
+            Set the initialisation flag for memorized attributes
+            true = the setpoint value will be written to the attribute on initialisation
+            false = only the attribute setpoint is initialised.
+            No action is taken on the attribute
+
+        Parameters :
+            - write_on_init : (bool) if true the setpoint value will be written
+                              to the attribute on initialisation
+        Return     : None
+    """ )
+
+    document_method("set_change_event", """
+    set_change_event(self, implemented, detect) -> None
+
+            Set a flag to indicate that the server fires change events manually
+            without the polling to be started for the attribute.
+            If the detect parameter is set to true, the criteria specified for
+            the change event are verified and the event is only pushed if they
+            are fullfilled.
+
+            If detect is set to false the event is fired without checking!
+
+        Parameters :
+            - implemented : (bool) True when the server fires change events manually.
+            - detect : (bool) Triggers the verification of the change event properties
+                       when set to true.
+        Return     : None
+    """ )
+
+    document_method("is_change_event", """
+    is_change_event(self) -> bool
+
+            Check if the change event is fired manually for this attribute.
+
+        Parameters : None
+        Return     : (bool) true if a manual fire change event is implemented.
+    """ )
+
+    document_method("is_check_change_criteria", """
+    is_check_change_criteria(self) -> bool
+
+            Check if the change event criteria should be checked when firing the event manually.
+
+        Parameters : None
+        Return     : (bool) true if a change event criteria will be checked.
+    """ )
+
+    document_method("set_archive_event", """
+    set_archive_event(self) -> None
+
+            Set a flag to indicate that the server fires archive events manually
+            without the polling to be started for the attribute If the detect
+            parameter is set to true, the criteria specified for the archive
+            event are verified and the event is only pushed if they are fullfilled.
+
+            If detect is set to false the event is fired without checking!
+
+        Parameters :
+            - implemented : (bool) True when the server fires change events manually.
+            - detect : (bool) Triggers the verification of the archive event properties
+                       when set to true.
+        Return     : None
+    """ )
+
+    document_method("is_archive_event", """
+    is_archive_event(self) -> bool
+
+            Check if the archive event is fired manually for this attribute.
+
+        Parameters : None
+        Return     : (bool) true if a manual fire archive event is implemented.
+    """ )
+
+    document_method("is_check_archive_criteria", """
+    is_check_archive_criteria(self) -> bool
+
+            Check if the archive event criteria should be checked when firing the event manually.
+
+        Parameters : None
+        Return     : (bool) true if a archive event criteria will be checked.
+    """ )
+
+    document_method("get_name", """
+    get_name(self) -> str
+
+            Get the attribute name.
+
+        Parameters : None
+        Return     : (str) the attribute name
+    """ )
+
+    document_method("get_format", """
+    get_format(self) -> AttrDataFormat
+
+            Get the attribute format
+
+        Parameters : None
+        Return     : (AttrDataFormat) the attribute format
+    """ )
+
+    document_method("get_writable", """
+    get_writable(self) -> AttrWriteType
+
+            Get the attribute write type
+
+        Parameters : None
+        Return     : (AttrWriteType) the attribute write type
+    """ )
+
+    document_method("get_type", """
+    get_type(self) -> int
+
+            Get the attribute data type
+
+        Parameters : None
+        Return     : (int) the attribute data type
+    """ )
+
+    document_method("get_disp_level", """
+    get_disp_level(self) -> DispLevel
+
+            Get the attribute display level
+
+        Parameters : None
+        Return     : (DispLevel) the attribute display level
+    """ )
+
+    document_method("get_polling_period", """
+    get_polling_period(self) -> int
+
+            Get the polling period (mS)
+
+        Parameters : None
+        Return     : (int) the polling period (mS)
+    """ )
+
+    document_method("get_memorized", """
+    get_memorized(self) -> bool
+
+            Determine if the attribute is memorized or not.
+
+        Parameters : None
+        Return     : (bool) True if the attribute is memorized
+    """ )
+
+    document_method("get_memorized_init", """
+    get_memorized_init(self) -> bool
+
+            Determine if the attribute is written at startup from the memorized value if
+            it is memorized
+
+        Parameters : None
+        Return     : (bool) True if initialized with memorized value or not
+    """ )
+
+    document_method("get_assoc", """
+    get_assoc(self) -> str
+
+            Get the associated name.
+
+        Parameters : None
+        Return     : (bool) the associated name
+    """ )
+
+    document_method("is_assoc", """
+    is_assoc(self) -> bool
+
+            Determine if it is assoc.
+
+        Parameters : None
+        Return     : (bool) if it is assoc
+    """ )
+
+    document_method("get_class_properties", """
+    get_class_properties(self) -> sequence<AttrProperty>
+
+            Get the class level attribute properties
+
+        Parameters : None
+        Return     : (sequence<AttrProperty>) the class attribute properties
+    """ )
+
+    document_method("get_user_default_properties", """
+    get_user_default_properties(self) -> sequence<AttrProperty>
+
+            Get the user default attribute properties
+
+        Parameters : None
+        Return     : (sequence<AttrProperty>) the user default attribute properties
+    """ )
+
+    document_method("set_class_properties", """
+    set_class_properties(self, props) -> None
+
+            Set the class level attribute properties
+
+        Parameters :
+            - props : (StdAttrPropertyVector) new class level attribute properties
+        Return     : None
+    """ )
+
+def __doc_UserDefaultAttrProp():
+    def document_method(method_name, desc, append=True):
+        return __document_method(UserDefaultAttrProp, method_name, desc, append)
+
+    UserDefaultAttrProp.__doc__ = """
+    User class to set attribute default properties.
+    This class is used to set attribute default properties. 
+    Three levels of attributes properties setting are implemented within Tango. 
+    The highest property setting level is the database. 
+    Then the user default (set using this UserDefaultAttrProp 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
+    """ )
+
+    document_method("set_format", """
+    set_format(self, def_format) -> None
+
+            Set default format property. 
+
+        Parameters : 
+            - def_format : (str) the user default format property 
+        Return     : None
+    """ )
+
+    document_method("set_unit", """
+    set_unit(self, def_unit) -> None
+
+            Set default unit property. 
+
+        Parameters : 
+            - def_unit : (str) te user default unit property 
+        Return     : None
+    """ )
+    
+    document_method("set_standard_unit", """
+    set_standard_unit(self, def_standard_unit) -> None
+
+            Set default standard unit property. 
+
+        Parameters :  
+            - def_standard_unit : (str) the user default standard unit property 
+        Return     : None
+    """ )
+    
+    document_method("set_display_unit", """
+    set_display_unit(self, def_display_unit) -> None
+
+            Set default display unit property. 
+
+        Parameters :  
+            - def_display_unit : (str) the user default display unit property 
+        Return     : None
+    """ )
+    
+    document_method("set_min_value", """
+    set_min_value(self, def_min_value) -> None
+
+            Set default min_value property. 
+
+        Parameters :  
+            - def_min_value : (str) the user default min_value property 
+        Return     : None
+    """ )
+    
+    document_method("set_max_value", """
+    set_max_value(self, def_max_value) -> None
+
+            Set default max_value property. 
+
+        Parameters :  
+            - def_max_value : (str) the user default max_value property 
+        Return     : None
+    """ )
+    
+    document_method("set_min_alarm", """
+    set_min_alarm(self, def_min_alarm) -> None
+
+            Set default min_alarm property. 
+
+        Parameters :  
+            - def_min_alarm : (str) the user default min_alarm property 
+        Return     : None
+    """ )
+    
+    document_method("set_max_alarm", """
+    set_max_alarm(self, def_max_alarm) -> None
+
+            Set default max_alarm property. 
+
+        Parameters :  
+            - def_max_alarm : (str) the user default max_alarm property 
+        Return     : None
+    """ )
+    
+    document_method("set_min_warning", """
+    set_min_warning(self, def_min_warning) -> None
+
+            Set default min_warning property. 
+
+        Parameters :  
+            - def_min_warning : (str) the user default min_warning property 
+        Return     : None
+    """ )
+    
+    document_method("set_max_warning", """
+    set_max_warning(self, def_max_warning) -> None
+
+            Set default max_warning property. 
+
+        Parameters :  
+            - def_max_warning : (str) the user default max_warning property 
+        Return     : None
+    """ )
+    
+    document_method("set_delta_t", """
+    set_delta_t(self, def_delta_t) -> None
+
+            Set default RDS alarm delta_t property. 
+
+        Parameters :  
+            - def_delta_t : (str) the user default RDS alarm delta_t property 
+        Return     : None
+    """ )
+    
+    document_method("set_delta_val", """
+    set_delta_val(self, def_delta_val) -> None
+
+            Set default RDS alarm delta_val property. 
+
+        Parameters :  
+            - def_delta_val : (str) the user default RDS alarm delta_val property 
+        Return     : None
+    """ )
+    
+    document_method("set_abs_change", """
+    set_abs_change(self, def_abs_change) -> None
+
+            Set default change event abs_change property. 
+
+        Parameters :  
+            - def_abs_change : (str) the user default change event abs_change property 
+        Return     : None
+    """ )
+    
+    document_method("set_rel_change", """
+    set_rel_change(self, def_rel_change) -> None
+
+            Set default change event rel_change property. 
+
+        Parameters :  
+            - def_rel_change : (str) the user default change event rel_change property 
+        Return     : None
+    """ )
+    
+    document_method("set_period", """ 
+    set_period(self, def_period) -> None
+
+            Set default periodic event period property. 
+
+        Parameters :  
+            - def_period : (str) the user default periodic event period property 
+        Return     : None
+    """ )
+
+    document_method("set_archive_abs_change", """
+    set_archive_abs_change(self, def_archive_abs_change) -> None
+
+            Set default archive event abs_change property. 
+
+        Parameters :  
+            - def_archive_abs_change : (str) the user default archive event abs_change property 
+        Return     : None
+    """ )
+
+    document_method("set_archive_rel_change", """
+    set_archive_rel_change(self, def_archive_rel_change) -> None
+
+            Set default archive event rel_change property. 
+
+        Parameters :  
+            - def_archive_rel_change : (str) the user default archive event rel_change property 
+        Return     : None
+    """ )
+    
+    document_method("set_archive_period", """
+    set_archive_period(self, def_archive_period) -> None
+
+            Set default archive event period property. 
+
+        Parameters :  
+            - def_archive_period : (str) t
+        Return     : None
+    """ )
+    
+def init(doc=True):
+    __init_DeviceImpl()
+    __init_Attribute()
+    __init_Attr()
+    __init_Logger()
+    if doc:
+        __doc_DeviceImpl()
+        __doc_extra_DeviceImpl(Device_3Impl)
+        __doc_extra_DeviceImpl(Device_4Impl)
+        __doc_Attribute()
+        __doc_WAttribute()
+        __doc_MultiAttribute()
+        __doc_UserDefaultAttrProp()
+        __doc_Attr()
diff --git a/PyTango/globals.py b/PyTango/globals.py
new file mode 100644
index 0000000..33d8f83
--- /dev/null
+++ b/PyTango/globals.py
@@ -0,0 +1,119 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = [ "get_class", "get_classes", "get_cpp_class", "get_cpp_classes",
+            "get_constructed_class", "get_constructed_classes",
+            "class_factory", "delete_class_list",
+            "class_list", "cpp_class_list", "constructed_class"]
+            
+__docformat__ = "restructuredtext"
+
+# list of tuple<DeviceClass class, DeviceImpl class, tango device class name>
+class_list = []
+
+# list of tuple<DeviceClass name, tango device class name>
+cpp_class_list = []
+
+# list of DeviceClass objects, one for each registered device class
+constructed_class = []
+
+def get_classes():
+    global class_list
+    return class_list
+
+def get_class(name):
+    for klass_info in get_classes():
+        if klass_info[2] == name:
+            return klass_info
+    return None
+
+def get_class_by_class(klass):
+    for klass_info in get_classes():
+        if klass_info[0] == klass:
+            return klass_info
+    return None
+
+def get_cpp_classes():
+    global cpp_class_list
+    return cpp_class_list
+
+def get_cpp_class(name):
+    for klass_info in get_cpp_classes():
+        if klass_info[1] == name:
+            return klass_info
+    return None
+
+def get_constructed_classes():
+    global constructed_class
+    return constructed_class
+
+def get_constructed_class(name):
+    for klass in get_constructed_classes():
+        if klass.get_name() == name:
+            return klass
+    return None
+
+def get_constructed_class_by_class(klass):
+    for k in get_constructed_classes():
+        if k.__class__ == klass:
+            return k
+    return None
+
+#
+# A method to delete Tango classes from Python
+#
+
+def delete_class_list():
+    global constructed_class
+    if len(constructed_class) != 0:
+       del(constructed_class[:])
+
+#
+# A generic class_factory method
+#
+
+def class_factory():
+    local_class_list = get_classes()
+    local_cpp_class_list = get_cpp_classes()
+
+    if ((len(local_class_list) + len(local_cpp_class_list)) == 0):
+        print 'Oups, no Tango class defined within this device server !!!'
+        print 'Sorry, but I exit'
+        import sys
+        sys.exit()
+
+    # Call the delete_class_list function in order to clear the global
+    # constructed class Python list. This is necessary only in case of
+    # ServerRestart command
+    delete_class_list()
+
+    local_constructed_class = get_constructed_classes()
+    for class_info in local_class_list:
+        device_class_class = class_info[0]
+        tango_device_class_name = class_info[2]
+        device_class = device_class_class(tango_device_class_name)
+        local_constructed_class.append(device_class)
+
diff --git a/PyTango/group.py b/PyTango/group.py
new file mode 100644
index 0000000..ea8aeba
--- /dev/null
+++ b/PyTango/group.py
@@ -0,0 +1,219 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = [ "Group" ]
+
+__docformat__ = "restructuredtext"
+
+import operator
+import types
+
+from _PyTango import __Group as _RealGroup, GroupElement
+from utils import document_method as __document_method
+
+import group_element
+
+# I define Group as a proxy to __Group, where group is the actual
+# C++ Tango::Group object. Most functions just call the __group object
+# and are defined dynamically in __init_proxy_Group, also copying it's
+# documentation strings.
+# The proxy is useful for add(group). In this case the parameter 'group'
+# becomes useless. With the proxy we make that parameter come to live
+# again before returning.
+# The other function that needs to be adapted to this is get_group because
+# we want to return a Group, not a __Group!
+class Group:
+    def __init__(self, name):
+        if isinstance(name, str):
+            name = _RealGroup(name)
+        if not isinstance(name, _RealGroup):
+            raise TypeError("Constructor expected receives a str")
+        self.__group = name
+
+    def add(self, pattern_subgroup, timeout_ms=-1):
+        if isinstance(pattern_subgroup, Group):
+            name = pattern_subgroup.__group.get_name()
+            self.__group.add(pattern_subgroup.__group, timeout_ms)
+            pattern_subgroup.__group = self.get_group(name)
+        else:
+            self.__group.add(pattern_subgroup, timeout_ms)
+
+    def get_group(self, group_name):
+        internal = self.__group.get_group(group_name)
+        if internal is None:
+            return None
+        return Group(internal)
+
+def __init_proxy_Group():
+    proxy_methods = [
+        #'add',
+        'command_inout',
+        'command_inout_asynch',
+        'command_inout_reply',
+        'contains',
+        'disable',
+        'enable',
+        'get_device',
+        'get_device_list',
+        'get_fully_qualified_name',
+        #'get_group',
+        'get_name',
+        'get_size',
+        'is_enabled',
+        'name_equals',
+        'name_matches',
+        'ping',
+        'read_attribute',
+        'read_attribute_asynch',
+        'read_attribute_reply',
+        'read_attributes',
+        'read_attributes_asynch',
+        'read_attributes_reply',
+        'remove',
+        'remove_all',
+        'set_timeout_millis',
+        'write_attribute',
+        'write_attribute_asynch',
+        'write_attribute_reply',
+        '__contains__',
+        '__delitem__',
+        '__getitem__',
+        '__len__']
+        
+    def proxy_call_define(fname):
+        def fn(self, *args, **kwds):
+            return getattr(self._Group__group, fname)(*args, **kwds)
+        fn.__doc__ = getattr(_RealGroup, fname).__doc__
+        setattr(Group, fname, fn)
+
+    for fname in proxy_methods:
+        proxy_call_define(fname)
+    
+    Group.add.im_func.__doc__ = _RealGroup.add.__doc__
+    Group.get_group.im_func.__doc__ = _RealGroup.get_group.__doc__
+    Group.__doc__ = _RealGroup.__doc__
+
+
+def __doc_Group():
+    def document_method(method_name, desc, append=True):
+        return __document_method(_RealGroup, method_name, desc, append)
+
+    document_method("add", GroupElement.add.__doc__, False)
+    document_method("add", """
+    add(self, subgroup, timeout_ms=-1) -> None
+        
+            Attaches a (sub)_RealGroup.
+            
+            To remove the subgroup use the remove() method.
+
+        Parameters :
+            - subgroup   : (str)
+            - timeout_ms : (int) If timeout_ms parameter is different from -1,
+                            the client side timeout associated to each device
+                            composing the _RealGroup added is set to timeout_ms
+                            milliseconds. If timeout_ms is -1, timeouts are
+                            not changed.
+        Return     : None
+
+        Throws     : TypeError, ArgumentError
+    """ )
+
+    document_method("remove_all", """
+    remove_all(self) -> None
+    
+        Removes all elements in the _RealGroup. After such a call, the _RealGroup is empty.
+    """ )
+
+    # I just documented them in group_element.py ...
+    #document_method("enable", """""" )
+    #document_method("disable", """""" )
+
+    document_method("get_device_list", """
+    get_device_list(self, forward=True) -> sequence<str>
+
+            Considering the following hierarchy:
+
+            ::
+        
+                g2.add("my/device/04")
+                g2.add("my/device/05")
+                
+                g4.add("my/device/08")
+                g4.add("my/device/09")
+                
+                g3.add("my/device/06")
+                g3.add(g4)
+                g3.add("my/device/07")
+                
+                g1.add("my/device/01")
+                g1.add(g2)
+                g1.add("my/device/03")
+                g1.add(g3)
+                g1.add("my/device/02")
+
+            The returned vector content depends on the value of the forward option.
+            If set to true, the results will be organized as follows:
+
+            ::
+        
+                    dl = g1.get_device_list(True)
+
+                dl[0] contains "my/device/01" which belongs to g1
+                dl[1] contains "my/device/04" which belongs to g1.g2
+                dl[2] contains "my/device/05" which belongs to g1.g2
+                dl[3] contains "my/device/03" which belongs to g1
+                dl[4] contains "my/device/06" which belongs to g1.g3
+                dl[5] contains "my/device/08" which belongs to g1.g3.g4
+                dl[6] contains "my/device/09" which belongs to g1.g3.g4
+                dl[7] contains "my/device/07" which belongs to g1.g3
+                dl[8] contains "my/device/02" which belongs to g1
+                
+            If the forward option is set to false, the results are:
+
+            ::
+        
+                    dl = g1.get_device_list(False);
+
+                dl[0] contains "my/device/01" which belongs to g1
+                dl[1] contains "my/device/03" which belongs to g1
+                dl[2] contains "my/device/02" which belongs to g1
+
+
+        Parameters :
+            - forward : (bool) If it is set to true (the default), the request
+                        is forwarded to sub-groups. Otherwise, it is only
+                        applied to the local set of devices.
+                
+        Return     : (sequence<str>) The list of devices currently in the hierarchy.
+        
+        Throws     :
+    """ )
+
+def init(doc=True):
+    group_element.init(doc=doc)
+    if doc:
+        __doc_Group()
+    __init_proxy_Group()
diff --git a/PyTango/group_element.py b/PyTango/group_element.py
new file mode 100644
index 0000000..cd4a6ef
--- /dev/null
+++ b/PyTango/group_element.py
@@ -0,0 +1,586 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = []
+            
+__docformat__ = "restructuredtext"
+
+import operator
+import types
+
+from _PyTango import StdStringVector
+from _PyTango import GroupElement
+
+from utils import document_method as __document_method
+from utils import seq_2_StdStringVector
+
+def __apply_to(fn, key):
+    if isinstance(key, slice):
+        if key.step:
+            return [ fn(x) for x in xrange(key.start, key.stop, key.step) ]
+        else:
+            return [ fn(x) for x in xrange(key.start, key.stop) ]
+    else:
+        return fn(key)
+
+def __GroupElement__contains(self, pattern):
+    return self.contains(pattern)
+
+def __GroupElement__get_one_item(self, key):
+    x = self.get_group(key)
+    if x is not None:
+        return x
+    return self.get_device(key)
+    
+def __GroupElement__getitem(self, key):
+    fn = lambda x: __GroupElement__get_one_item(self, x)
+    return __apply_to(fn, key)
+
+def __GroupElement__delitem(self, key):
+    fn = lambda x: self.remove(x)
+    return __apply_to(fn, key)
+
+def __GroupElement__len(self):
+    return self.get_size()
+
+def __GroupElement__add(self, patterns_or_group, timeout_ms=-1):
+    if isinstance(patterns_or_group, GroupElement):
+        return self.__add(patterns_or_group, timeout_ms)
+    elif isinstance(patterns_or_group, StdStringVector):
+        return self.__add(patterns_or_group, timeout_ms)
+    elif isinstance(patterns_or_group, str):
+        return self.__add(patterns_or_group, timeout_ms)
+    elif operator.isSequenceType(patterns_or_group):
+        patterns = seq_2_StdStringVector(patterns_or_group)
+        return self.__add(patterns, timeout_ms)
+    else:
+        raise TypeError('Parameter patterns_or_group: Should be GroupElement, str or a sequence of strings.')
+    
+def __GroupElement__remove(self, patterns, forward=True):
+    if isinstance(patterns, str):
+        return self.__remove(patterns, forward)
+    elif operator.isSequenceType(patterns):
+        std_patterns = seq_2_StdStringVector(patterns)
+        return self.__remove(std_patterns, forward)
+    else:
+        raise TypeError('Parameter patterns: Should be a str or a sequence of str.')
+
+def __GroupElement__comand_inout(self, cmd_name, param=None, forward=True):
+    if param is None:
+        idx = self.command_inout_asynch(cmd_name, forget=False, forward=forward, reserved=-1)
+    else:
+        idx = self.command_inout_asynch(cmd_name, param, forget=False, forward=forward, reserved=-1)
+    return self.command_inout_reply(idx)
+
+def __GroupElement__read_attribute(self, attr_name, forward=True):
+    idx = self.read_attribute_asynch(attr_name, forward, reserved=-1)
+    return self.read_attribute_reply(idx)
+
+def __GroupElement__read_attributes(self, attr_names, forward=True):
+    idx = self.read_attributes_asynch(attr_names, forward, reserved=-1)
+    return self.read_attributes_reply(idx)
+
+def __GroupElement__write_attribute(self, attr_name, value, forward=True):
+    idx = self.write_attribute_asynch(attr_name, value, forward, reserved=-1)
+    return self.write_attribute_reply(idx)
+
+def __init_GroupElement():
+    
+    GroupElement.__contains__ = __GroupElement__contains
+    GroupElement.__getitem__ = __GroupElement__getitem
+    GroupElement.__delitem__ = __GroupElement__delitem
+    GroupElement.__len__ = __GroupElement__len
+
+    GroupElement.add = __GroupElement__add
+    GroupElement.remove = __GroupElement__remove
+    
+    GroupElement.command_inout = __GroupElement__comand_inout
+    GroupElement.read_attribute = __GroupElement__read_attribute
+    GroupElement.read_attributes = __GroupElement__read_attributes
+    GroupElement.write_attribute = __GroupElement__write_attribute
+
+def __doc_GroupElement():
+    def document_method(method_name, desc, append=True):
+        return __document_method(GroupElement, method_name, desc, append)
+    
+    document_method("add", """
+    add(self, patterns, timeout_ms=-1) -> None
+        
+            Attaches any device which name matches one of the specified patterns.
+
+            This method first asks to the Tango database the list of device names
+            matching one the patterns. Devices are then attached to the group in
+            the order in which they are returned by the database.
+
+            Any device already present in the hierarchy (i.e. a device belonging to
+            the group or to one of its subgroups), is silently ignored but its
+            client side timeout is set to timeout_ms milliseconds if timeout_ms
+            is different from -1.
+
+        Parameters :
+            - patterns   : (str | sequence<str>) can be a simple device name or
+                            a device name pattern (e.g. domain_*/ family/member_*),
+                            or a sequence of these.
+            - timeout_ms : (int) If timeout_ms is different from -1, the client
+                            side timeouts of all devices matching the
+                            specified patterns are set to timeout_ms
+                            milliseconds.
+        Return     : None
+
+        Throws     : TypeError, ArgumentError
+    """ )
+
+
+
+    document_method("remove", """
+    remove(self, patterns, forward=True) -> None
+        
+            Removes any group or device which name matches the specified pattern. 
+            
+            The pattern parameter can be a group name, a device name or a device
+            name pattern (e.g domain_*/family/member_*).
+            
+            Since we can have groups with the same name in the hierarchy, a group
+            name can be fully qualified to specify which group should be removed.
+            Considering the following group:
+
+                ::
+
+                    -> gauges 
+                    | -> cell-01 
+                    |     |-> penning 
+                    |     |    |-> ...
+                    |     |-> pirani
+                    |          |-> ...
+                    | -> cell-02
+                    |     |-> penning
+                    |     |    |-> ...
+                    |     |-> pirani
+                    |          |-> ...
+                    | -> cell-03
+                    |     |-> ... 
+                    |     
+                    | -> ...  
+            
+            A call to gauges->remove("penning") will remove any group named
+            "penning" in the hierarchy while gauges->remove("gauges.cell-02.penning")
+            will only remove the specified group.
+        
+        Parameters :
+            - patterns   : (str | sequence<str>) A string with the pattern or a
+                            list of patterns.
+            - forward    : (bool) If fwd is set to true (the default), the remove
+                            request is also forwarded to subgroups. Otherwise,
+                            it is only applied to the local set of elements.
+                            For instance, the following code remove any
+                            stepper motor in the hierarchy:
+                                root_group->remove("*/stepper_motor/*");
+                
+        Return     : None
+        
+        Throws     : 
+    """ )
+
+    document_method("contains", """
+    contains(self, pattern, forward=True) -> bool
+        
+        Parameters :
+            - pattern    : (str) The pattern can be a fully qualified or simple
+                            group name, a device name or a device name pattern.
+            - forward    : (bool) If fwd is set to true (the default), the remove
+                            request is also forwarded to subgroups. Otherwise,
+                            it is only applied to the local set of elements.
+                
+        Return     : (bool) Returns true if the hierarchy contains groups and/or
+                     devices which name matches the specified pattern. Returns
+                     false otherwise.
+        
+        Throws     : 
+    """ )
+
+
+    document_method("get_device", """
+    get_device(self, dev_name) -> DeviceProxy
+    get_device(self, idx) -> DeviceProxy
+
+            Returns a reference to the specified device or None if there is no
+            device by that name in the group. Or, returns a reference to the
+            "idx-th" device in the hierarchy or NULL if the hierarchy contains
+            less than "idx" devices.
+
+            This method may throw an exception in case the specified device belongs
+            to the group but can't be reached (not registered, down...). See example
+            below:
+
+            ::
+
+                try:
+                    dp = g.get_device("my/device/01")
+                    if dp is None:
+                        # my/device/01 does not belong to the group
+                        pass
+                except DevFailed, f:
+                    # my/device/01 belongs to the group but can't be reached
+                    pass
+
+            The request is systematically forwarded to subgroups (i.e. if no device
+            named device_name could be found in the local set of devices, the
+            request is forwarded to subgroups).
+            
+        Parameters :
+            - dev_name    : (str) Device name.
+            - idx         : (int) Device number.
+                
+        Return     : (DeviceProxy) Be aware that this method returns a
+                    different DeviceProxy referring to the same device each time.
+                    So, do not use it directly for permanent things.
+
+        Example:
+                        # WRONG: The DeviceProxy will quickly go out of scope
+                        # and disappear (thus, the event will be automatically
+                        # unsubscribed)
+                        g.get_device("my/device/01").subscribe_events('attr', callback)
+
+                        # GOOD:
+                        dp = g.get_device("my/device/01")
+                        dp.subscribe_events('attr', callback)
+        
+        Throws     : DevFailed
+    """ )
+
+    document_method("get_group", """
+    get_group(self, group_name ) -> Group
+
+            Returns a reference to the specified group or None if there is no group
+            by that name. The group_name can be a fully qualified name.
+
+            Considering the following group:
+
+            ::
+                    
+                -> gauges
+                    |-> cell-01
+                    |    |-> penning
+                    |    |    |-> ... 
+                    |    |-> pirani
+                    |    |-> ... 
+                    |-> cell-02
+                    |    |-> penning
+                    |    |    |-> ...
+                    |    |-> pirani
+                    |    |-> ...
+                    | -> cell-03
+                    |    |-> ...
+                    |
+                    | -> ...  
+
+            A call to gauges.get_group("penning") returns the first group named
+            "penning" in the hierarchy (i.e. gauges.cell-01.penning) while
+            gauges.get_group("gauges.cell-02.penning'') returns the specified group.
+            
+            The request is systematically forwarded to subgroups (i.e. if no group
+            named group_name could be found in the local set of elements, the request
+            is forwarded to subgroups).
+        
+        Parameters :
+            - group_name : (str)
+        
+        Return     : (Group)
+        
+        Throws     :
+        
+        New in PyTango 7.0.0
+    """ )
+
+    
+# Tango methods (~ DeviceProxy interface)
+    document_method("ping", """
+    ping(self, forward=True) -> bool
+
+            Ping all devices in a group.
+        
+        Parameters :
+            - forward    : (bool) If fwd is set to true (the default), the request
+                            is also forwarded to subgroups. Otherwise, it is
+                            only applied to the local set of devices.
+                
+        Return     : (bool) This method returns true if all devices in
+        the group are alive, false otherwise.
+        
+        Throws     : 
+    """ )
+
+    document_method("set_timeout_millis", """
+    set_timeout_millis(self, timeout_ms) -> bool
+        
+            Set client side timeout for all devices composing the group in
+            milliseconds. Any method which takes longer than this time to execute
+            will throw an exception.
+
+        Parameters :
+            - timeout_ms : (int)
+                
+        Return     : None
+        
+        Throws     : (errors are ignored)
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("command_inout_asynch", """
+    command_inout_asynch(self, cmd_name, forget=False, forward=True, reserved=-1 ) -> int
+    command_inout_asynch(self, cmd_name, param=None forget=False, forward=True, reserved=-1 ) -> int
+        
+            Executes a Tango command on each device in the group asynchronously.
+            The method sends the request to all devices and returns immediately.
+            Pass the returned request id to Group.command_inout_reply() to obtain
+            the results.
+
+        Parameters :
+            - cmd_name : (str) Command name
+            - param    : (any)
+            - forget   : (bool) Fire and forget flag. If set to true, it means that
+                            no reply is expected (i.e. the caller does not care
+                            about it and will not even try to get it)
+            - forward  : (bool) If it is set to true (the default) request is
+                            forwarded to subgroups. Otherwise, it is only applied
+                            to the local set of devices.
+            - reserved : (int) is reserved for internal purpose and should not be
+                            used. This parameter may disappear in a near future.
+                
+        Return     : (int) request id. Pass the returned request id to
+                    Group.command_inout_reply() to obtain the results.
+        
+        Throws     :
+    """ )
+
+    document_method("command_inout_reply", """
+    command_inout_reply(self, req_id, timeout_ms=0) -> sequence<GroupCmdReply>
+
+            Returns the results of an asynchronous command.
+
+        Parameters :
+            - req_id     : (int) Is a request identifier previously returned by one
+                            of the command_inout_asynch methods
+            - timeout_ms : (int) For each device in the hierarchy, if the command
+                            result is not yet available, command_inout_reply
+                            wait timeout_ms milliseconds before throwing an
+                            exception. This exception will be part of the
+                            global reply. If timeout_ms is set to 0,
+                            command_inout_reply waits "indefinitely".
+                
+        Return     : (sequence<GroupCmdReply>)
+        
+        Throws     : 
+    """ )
+
+    document_method("command_inout", """
+    command_inout(   self, cmd_name, param=None, forward=True) -> sequence<GroupCmdReply>
+
+            Just a shortcut to do:
+                self.command_inout_reply(self.command_inout_asynch(...))
+
+        Parameters:
+            - cmd_name : (str)
+            - param    : (any)
+            - forward  : (bool)
+
+        Return : (sequence<GroupCmdReply>)
+    """ )
+
+    document_method("read_attribute_asynch", """
+    read_attribute_asynch(self, attr_name, forward=True, reserved=-1 ) -> int
+
+            Reads an attribute on each device in the group asynchronously.
+            The method sends the request to all devices and returns immediately.
+
+        Parameters :
+            - attr_name : (str) Name of the attribute to read.
+            - forward   : (bool) If it is set to true (the default) request is
+                            forwarded to subgroups. Otherwise, it is only applied
+                            to the local set of devices.
+            - reserved  : (int) is reserved for internal purpose and should not be
+                            used. This parameter may disappear in a near future.
+                
+        Return     : (int) request id. Pass the returned request id to
+                    Group.read_attribute_reply() to obtain the results.
+        
+        Throws     :
+    """ )
+
+    document_method("read_attributes_asynch", """
+    read_attributes_asynch(self, attr_names, forward=True, reserved=-1 ) -> int
+
+            Reads the attributes on each device in the group asynchronously.
+            The method sends the request to all devices and returns immediately.
+
+        Parameters :
+            - attr_names : (sequence<str>) Name of the attributes to read.
+            - forward    : (bool) If it is set to true (the default) request is
+                            forwarded to subgroups. Otherwise, it is only applied
+                            to the local set of devices.
+            - reserved   : (int) is reserved for internal purpose and should not be
+                            used. This parameter may disappear in a near future.
+                
+        Return     : (int) request id. Pass the returned request id to
+                    Group.read_attributes_reply() to obtain the results.
+        
+        Throws     :
+    """ )
+
+    document_method("read_attribute_reply", """
+    read_attribute_reply(self, req_id, timeout_ms=0 ) -> sequence<GroupAttrReply>
+
+            Returns the results of an asynchronous attribute reading.
+
+        Parameters :
+            - req_id     : (int) a request identifier previously returned by read_attribute_asynch.
+            - timeout_ms : (int) For each device in the hierarchy, if the attribute
+                            value is not yet available, read_attribute_reply
+                            wait timeout_ms milliseconds before throwing an
+                            exception. This exception will be part of the
+                            global reply. If timeout_ms is set to 0,
+                            read_attribute_reply waits "indefinitely".
+                
+        Return     : (sequence<GroupAttrReply>)
+        
+        Throws     :
+    """ )
+
+    document_method("read_attributes_reply", """
+    read_attributes_reply(self, req_id, timeout_ms=0 ) -> sequence<GroupAttrReply>
+
+            Returns the results of an asynchronous attribute reading.
+
+        Parameters :
+            - req_id     : (int) a request identifier previously returned by read_attribute_asynch.
+            - timeout_ms : (int) For each device in the hierarchy, if the attribute
+                            value is not yet available, read_attribute_reply
+                            wait timeout_ms milliseconds before throwing an
+                            exception. This exception will be part of the
+                            global reply. If timeout_ms is set to 0,
+                            read_attributes_reply waits "indefinitely".
+                
+        Return     : (sequence<GroupAttrReply>)
+        
+        Throws     :
+    """ )
+
+    document_method("read_attribute", """
+    read_attribute(  self, attr_name, forward=True) -> sequence<GroupAttrReply>
+
+            Just a shortcut to do:
+                self.read_attribute_reply(self.read_attribute_asynch(...))
+    """ )
+
+    document_method("read_attributes", """
+    read_attributes( self, attr_names, forward=True) -> sequence<GroupAttrReply>
+
+            Just a shortcut to do:
+                self.read_attributes_reply(self.read_attributes_asynch(...))
+    """ )
+
+    document_method("write_attribute_asynch", """
+    write_attribute_asynch(self, attr_name, value, forward=True, reserved=-1 ) -> int
+
+            Writes an attribute on each device in the group asynchronously.
+            The method sends the request to all devices and returns immediately.
+
+        Parameters :
+            - attr_name : (str) Name of the attribute to write.
+            - value     : (any) Value to write. See DeviceProxy.write_attribute
+            - forward   : (bool) If it is set to true (the default) request is
+                            forwarded to subgroups. Otherwise, it is only applied
+                            to the local set of devices.
+            - reserved  : (int) is reserved for internal purpose and should not
+                            be used. This parameter may disappear in a near
+                            future.
+                
+        Return     : (int) request id. Pass the returned request id to
+                    Group.write_attribute_reply() to obtain the acknowledgements.
+        
+        Throws     :
+    """ )
+        
+    document_method("write_attribute_reply", """
+    write_attribute_reply(self, req_id, timeout_ms=0 ) -> sequence<GroupReply>
+
+            Returns the acknowledgements of an asynchronous attribute writing.
+
+        Parameters :
+            - req_id     : (int) a request identifier previously returned by write_attribute_asynch.
+            - timeout_ms : (int) For each device in the hierarchy, if the acknowledgment
+                            is not yet available, write_attribute_reply
+                            wait timeout_ms milliseconds before throwing an
+                            exception. This exception will be part of the
+                            global reply. If timeout_ms is set to 0,
+                            write_attribute_reply waits "indefinitely".
+                
+        Return     : (sequence<GroupReply>)
+        
+        Throws     :
+    """ )
+        
+    document_method("write_attribute", """
+    write_attribute( self, attr_name, value, forward=True) -> sequence<GroupReply>
+
+            Just a shortcut to do:
+                self.write_attribute_reply(self.write_attribute_asynch(...))
+    """ )
+
+# Misc methods
+    document_method("get_name", """
+        Get the name of the group. Eg: Group('name').get_name() == 'name'
+    """ )
+    document_method("get_fully_qualified_name", """
+        Get the complete (dpt-separated) name of the group. This takes into
+        consideration the name of the group and its parents.
+    """ )
+    document_method("enable", "Enables a group or a device element in a group.")
+    document_method("disable", "Disables a group or a device element in a group.")
+    document_method("is_enabled", "Check if a group is enabled.\nNew in PyTango 7.0.0")
+    document_method("name_equals", "New in PyTango 7.0.0")
+    document_method("name_matches", "New in PyTango 7.0.0")
+    document_method("get_size", """
+    get_size(self, forward=True) -> int
+
+        Parameters :
+            - forward : (bool) If it is set to true (the default), the request is
+                        forwarded to sub-groups.
+                
+        Return     : (int) The number of the devices in the hierarchy
+        
+        Throws     :
+    """ )
+
+# "Should not be used" methods
+    # get_parent(self)
+    
+
+def init(doc=True):
+    __init_GroupElement()
+    if doc:
+        __doc_GroupElement()
diff --git a/PyTango/group_reply.py b/PyTango/group_reply.py
new file mode 100644
index 0000000..3cd1e55
--- /dev/null
+++ b/PyTango/group_reply.py
@@ -0,0 +1,114 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = []
+            
+__docformat__ = "restructuredtext"
+
+from utils import document_method as __document_method
+from _PyTango import GroupReply
+from _PyTango import GroupCmdReply
+from _PyTango import GroupAttrReply
+from _PyTango import ExtractAs
+
+def __GroupCmdReply__get_data(self):
+    return self.get_data_raw().extract()
+
+def __GroupAttrReply__get_data(self, extract_as=ExtractAs.Numpy):
+    # GroupAttrReply.__get_data() extracts the data from the object, so
+    # two successive calls to get_data() result in the second one returning
+    # an empty value, which is an unexpected behaviour.
+    # That's why we cache the result of the first call.
+    try:
+        data, orig_extract_as = self.__dataCache
+    except AttributeError:
+        data = self.__get_data(extract_as)
+        self.__dataCache = data, extract_as
+        return data
+    
+    if extract_as != orig_extract_as:
+        raise Exception("Successive calls to get_data() must receive the same"
+                        " parameters as the first one.")
+    return data
+
+def __init_GroupReply():
+    GroupCmdReply.get_data = __GroupCmdReply__get_data
+    GroupAttrReply.get_data = __GroupAttrReply__get_data
+
+def __doc_GroupReply():
+    def document_method(method_name, desc, append=True):
+        return __document_method(GroupReply, method_name, desc, append)
+
+    GroupReply.__doc__ = """
+        This is the base class for the result of an operation on a
+        PyTangoGroup, being it a write attribute, read attribute, or
+        command inout operation.
+
+        It has some trivial common operations:
+
+            - has_failed(self) -> bool
+            - group_element_enabled(self) ->bool
+            - dev_name(self) -> str
+            - obj_name(self) -> str
+            - get_err_stack(self) -> DevErrorList
+    """
+
+    __document_method(GroupCmdReply, "get_data", """
+    get_data(self) -> any
+
+            Get the actual value stored in the GroupCmdRply, the command
+            output value.
+            It's the same as self.get_data_raw().extract()
+
+        Parameters : None
+        Return     : (any) Whatever is stored there, or None.
+    """ )
+
+    __document_method(GroupCmdReply, "get_data_raw", """
+    get_data_raw(self) -> any
+
+            Get the DeviceData containing the output parameter
+            of the command.
+
+        Parameters : None
+        Return     : (DeviceData) Whatever is stored there, or None.
+    """ )
+
+    __document_method(GroupAttrReply, "get_data", """
+    get_data(self, extract_as=ExtractAs.Numpy) -> DeviceAttribute
+
+            Get the DeviceAttribute.
+
+        Parameters :
+            - extract_as : (ExtractAs)
+
+        Return     : (DeviceAttribute) Whatever is stored there, or None.
+    """ )
+
+def init(doc=True):
+    __init_GroupReply()
+    if doc:
+        __doc_GroupReply()
diff --git a/PyTango/group_reply_list.py b/PyTango/group_reply_list.py
new file mode 100644
index 0000000..db61348
--- /dev/null
+++ b/PyTango/group_reply_list.py
@@ -0,0 +1,98 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = []
+
+__docformat__ = "restructuredtext"
+
+from utils import document_method as __document_method
+from _PyTango import GroupReplyList
+from _PyTango import GroupCmdReplyList
+from _PyTango import GroupAttrReplyList
+
+def __GroupReplyList__getitem(self, item):
+    # Accessing an item in GroupReplyList and friends makes a C++ copy
+    # of the item calling the copy constructor. But the copy constructor
+    # of GroupReply is not fair: It extracts the data from the original
+    # object!! So, we will only call the original getitem once, the
+    # successive calls will just return the cached object.
+    # GroupReplyList could be changed to use proxies to the internal
+    # c++ object with the apropriate parameter to the
+    # boost::vector_indexing_suite, but when the value is extracted
+    # it is not anymore in any C++ object but in the python object, so
+    # we must still keep it.
+    
+    # Slices support
+    if isinstance(item, slice):
+        return [self.__getitem__(x) for x in xrange(*item.indices(len(self)))]
+    
+    # We want to get the same cache value for x[-1] as for x[len(x)-1]
+    if item < 0:
+        item = item + len(self)
+    
+    # Try to get from cache
+    try:
+        return self.__listCache[item]
+    except AttributeError:
+        # The GroupReplyList object is created without the
+        # cache attribute, so it is created here
+        self.__listCache = dict()
+    except KeyError:
+        # The decision wheter we are out of bounds or it's just a cache
+        # miss will be taken by original_getitem
+        pass
+
+    r = self.__GroupReplyList_original_getitem(item)
+    self.__listCache[item] = r
+    return r
+
+def __GroupReplyList__iter(self):
+    # Same problem as getitem. In this case it is easier for me to just
+    # reimplement __iter__ in terms of __getitem__
+    for x in xrange(len(self)):
+        yield self[x]
+
+def __init_GroupReplyList():
+    GroupReplyList.__GroupReplyList_original_getitem = GroupReplyList.__getitem__
+    GroupReplyList.__getitem__ = __GroupReplyList__getitem
+
+    GroupCmdReplyList.__GroupReplyList_original_getitem = GroupCmdReplyList.__getitem__
+    GroupCmdReplyList.__getitem__ = __GroupReplyList__getitem
+
+    GroupAttrReplyList.__GroupReplyList_original_getitem = GroupAttrReplyList.__getitem__
+    GroupAttrReplyList.__getitem__ = __GroupReplyList__getitem
+
+    GroupReplyList.__iter__ = __GroupReplyList__iter
+    GroupCmdReplyList.__iter__ = __GroupReplyList__iter
+    GroupAttrReplyList.__iter__ = __GroupReplyList__iter
+
+def __doc_GroupReplyList():
+    pass
+
+def init(doc=True):
+    __init_GroupReplyList()
+    if doc:
+        __doc_GroupReplyList()
diff --git a/PyTango/ipython/__init__.py b/PyTango/ipython/__init__.py
new file mode 100644
index 0000000..e56afa1
--- /dev/null
+++ b/PyTango/ipython/__init__.py
@@ -0,0 +1,25 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+from ipython import *
+
+from ipy_install import install
\ No newline at end of file
diff --git a/PyTango/ipython/ipy_cli.py b/PyTango/ipython/ipy_cli.py
new file mode 100644
index 0000000..c449165
--- /dev/null
+++ b/PyTango/ipython/ipy_cli.py
@@ -0,0 +1,82 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+import re
+import StringIO
+
+import IPython.genutils
+
+class EventLogger(object):
+    
+    def __init__(self, capacity=100000):
+        self._capacity = capacity
+        self._records = []
+        
+    def push_event(self, evt):
+        attr_name = evt.attr_name
+        dev, sep, attr = attr_name.rpartition('/')
+        if dev.startswith("tango://"):
+            dev = dev[8:]
+        if dev.count(":"):
+            # if it has tango host
+            host, sep, dev = dev.partition('/')
+        else:
+            host = "-----"
+        evt.host = host
+        evt.dev_name = dev
+        evt.s_attr_name = attr
+        self._records.append(evt)
+        over = len(self._records) - self._capacity
+        if over > 0:
+            self._records = self._records[over:]
+    
+    def model(self):
+        return self
+    
+    def getEvents(self):
+        return self._records
+    
+    def show(self, dexpr=None, aexpr=None):
+        if dexpr is not None:
+            dexpr = re.compile(dexpr, re.IGNORECASE)
+        if aexpr is not None:
+            aexpr = re.compile(aexpr, re.IGNORECASE)
+            
+        s = StringIO.StringIO()
+        cols = 4, 30, 18, 20, 12, 16
+        l = "%{0}s %{1}s %{2}s %{3}s %{4}s %{5}s".format(*cols)
+        print >>s, l % ('ID', 'Device', 'Attribute', 'Value', 'Quality', 'Time')
+        print >>s, l % (cols[0]*"-", cols[1]*"-", cols[2]*"-", cols[3]*"-", cols[4]*"-", cols[5]*"-")
+        for i,r in enumerate(self._records):
+            if dexpr is not None and not dexpr.match(r.dev_name): continue
+            if aexpr is not None and not aexpr.match(r.s_attr_name): continue
+            if r.err:
+                v = r.errors[0].reason
+                q = 'ERROR'
+                ts = r.reception_date.strftime("%H:%M:%S.%f")
+            else:
+                v = str(r.attr_value.value)
+                q = str(r.attr_value.quality)
+                ts = r.attr_value.time.strftime("%H:%M:%S.%f")
+            print >>s, l % (i, r.dev_name, r.s_attr_name, v, q, ts)
+        s.seek(0)
+        IPython.genutils.page(s.read())
\ No newline at end of file
diff --git a/PyTango/ipython/ipy_install.py b/PyTango/ipython/ipy_install.py
new file mode 100644
index 0000000..cc029e7
--- /dev/null
+++ b/PyTango/ipython/ipy_install.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+import sys
+import os
+import StringIO
+
+import IPython.genutils
+import PyTango
+
+__PROFILE = """\
+#!/usr/bin/env ipython
+\"\"\"An automaticaly generated IPython profile designed to provide a user 
+friendly interface to Tango.
+Created with PyTango {pytangover} for IPython {ipyver}\"\"\"
+
+import IPython
+import PyTango.ipython
+
+ip = IPython.ipapi.get()
+PyTango.ipython.init_ipython(ip)
+
+"""
+
+def install(ipydir=None,verbose=True):
+    install_dir = ipydir or IPython.genutils.get_ipython_dir()
+    f_name = os.path.join(install_dir, 'ipy_profile_spock.py')
+    if verbose:
+        out = sys.stdout
+    else:
+        out = StringIO.StringIO()
+    if ipydir is None and os.path.isfile(f_name):
+        print "Warning: The file '%s' already exists." % f_name
+        r = ''
+        while r.lower() not in ('y', 'n'):
+            r = raw_input("Do you wish to override it [Y/n]?")
+            r = r or 'y'
+        if r.lower() == 'n':
+            return
+    profile = __PROFILE.format(pytangover=PyTango.Release.version, ipyver=IPython.Release.version)
+    
+    out.write("Installing spock extension to ipython... ")
+    out.flush()
+    try:
+        f = file(f_name, "w")
+        f.write(profile)
+        f.close()
+        out.write("[DONE]\n\n")
+    except Exception, e:
+        out.write("[FAILED]\n\n")
+        raise e
+    
+    ipy_user_config = os.path.join(IPython.genutils.get_ipython_dir(), 'ipy_user_conf.py')
+    out.write("""\
+To start spock simply type on the command line:
+%% ipython -p spock
+
+If you want spock extension to be automaticaly active when you start ipython,
+edit your %s and add the line:
+import ipy_profile_spock
+
+Next time, just start ipython on the command line:
+%% ipython
+
+and your spock extension should be loaded automaticaly. Note that if you are also
+loading other extensions that, for example, overwrite the prompt, the prompt
+that will appear is the one from the last extension to be imported.
+
+For more information goto: http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+Have fun with spock!
+The PyTango team
+    """ % (ipy_user_config,))
+
+def main():
+    d = None
+    if len(sys.argv) > 1:
+        d = sys.argv[1]
+    install(d)
+    
+if __name__ == "__main__":
+    main()
diff --git a/PyTango/ipython/ipy_qt.py b/PyTango/ipython/ipy_qt.py
new file mode 100644
index 0000000..e8afe84
--- /dev/null
+++ b/PyTango/ipython/ipy_qt.py
@@ -0,0 +1,387 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+import operator
+import logging
+import time
+import datetime
+import PyTango
+import PyQt4.Qt as Qt
+
+BRUSH = Qt.QBrush
+COLOR = Qt.QColor
+_WhiteBrush = Qt.QBrush(Qt.Qt.white)
+_BlackBrush = Qt.QBrush(Qt.Qt.black)
+_RedBrush = Qt.QBrush(Qt.Qt.red)
+_GreenBrush = Qt.QBrush(Qt.Qt.green)
+_DarkGreenBrush = Qt.QBrush(Qt.Qt.darkGreen)
+_BlueBrush = Qt.QBrush(Qt.Qt.blue)
+_YellowBrush = Qt.QBrush(Qt.Qt.yellow)
+_MagentaBrush = Qt.QBrush(Qt.Qt.magenta)
+_GrayBrush = Qt.QBrush(Qt.Qt.gray)
+_DarkGrayBrush = Qt.QBrush(Qt.Qt.darkGray)
+_LightGrayBrush = Qt.QBrush(Qt.Qt.lightGray)
+
+ATTR_QUALITY_DATA = {
+    PyTango.AttrQuality.ATTR_INVALID  : (BRUSH(COLOR(128, 128,  128)), _WhiteBrush),
+    PyTango.AttrQuality.ATTR_VALID    : (_GreenBrush, _BlackBrush),
+    PyTango.AttrQuality.ATTR_ALARM    : (BRUSH(COLOR(255, 140,   0)), _WhiteBrush),
+    PyTango.AttrQuality.ATTR_WARNING  : (BRUSH(COLOR(255, 140,   0)), _WhiteBrush),
+    PyTango.AttrQuality.ATTR_CHANGING : (BRUSH(COLOR(128, 160, 255)), _BlackBrush),
+    None                              : (BRUSH(Qt.Qt.FDiagPattern), _BlackBrush)
+}
+
+DEVICE_STATE_DATA = {
+    PyTango.DevState.ON      : (_GreenBrush, _BlackBrush),
+    PyTango.DevState.OFF     : (_WhiteBrush, _BlackBrush),
+    PyTango.DevState.CLOSE   : (_WhiteBrush, _DarkGreenBrush),
+    PyTango.DevState.OPEN    : (_GreenBrush, _BlackBrush),
+    PyTango.DevState.INSERT  : (_WhiteBrush, _BlackBrush),
+    PyTango.DevState.EXTRACT : (_GreenBrush, _BlackBrush),
+    PyTango.DevState.MOVING  : (BRUSH(COLOR(128, 160, 255)), _BlackBrush),
+    PyTango.DevState.STANDBY : (_YellowBrush, _BlackBrush),
+    PyTango.DevState.FAULT   : (_RedBrush, _BlackBrush),
+    PyTango.DevState.INIT    : (BRUSH(COLOR(204, 204, 122)), _BlackBrush),
+    PyTango.DevState.RUNNING : (BRUSH(COLOR(128, 160, 255)), _BlackBrush),
+    PyTango.DevState.ALARM   : (BRUSH(COLOR(255, 140,   0)), _WhiteBrush),
+    PyTango.DevState.DISABLE : (_MagentaBrush, _BlackBrush),
+    PyTango.DevState.UNKNOWN : (_GrayBrush, _BlackBrush),
+    None                     : (_GrayBrush, _BlackBrush),
+}
+
+def getBrushForQuality(q):
+    return ATTR_QUALITY_DATA[q]
+
+def getBrushForState(s):
+    return DEVICE_STATE_DATA[s]
+
+def deviceAttributeValueStr(da):
+    return str(da.value)
+
+ID, HOST, DEVICE, ATTRIBUTE, VALUE, TIME = range(6)
+HORIZ_HEADER = 'ID', 'Host','Device','Attribute', 'Value', 'Time'
+
+class EventLoggerTableModel(Qt.QAbstractTableModel, logging.Handler):
+    
+    DftOddRowBrush = Qt.QBrush(Qt.QColor(220,220,220)), Qt.QBrush(Qt.Qt.black)
+    DftEvenRowBrush = Qt.QBrush(Qt.QColor(255,255,255)), Qt.QBrush(Qt.Qt.black)
+
+    DftColHeight = 20
+
+    DftColSize = Qt.QSize(50, DftColHeight), Qt.QSize(120, DftColHeight), \
+                 Qt.QSize(160, DftColHeight), Qt.QSize(100, DftColHeight), \
+                 Qt.QSize(120, DftColHeight), Qt.QSize(120, DftColHeight)
+    
+    def __init__(self, capacity=20, freq=0.1):
+        super(Qt.QAbstractTableModel, self).__init__()
+        logging.Handler.__init__(self)
+        self._capacity = capacity
+        self._records = []
+        self._accumulated_records = []
+        self.startTimer(freq*1000)
+
+    # ---------------------------------
+    # Qt.QAbstractTableModel overwrite
+    # ---------------------------------
+    
+#    def sort(self, column, order = Qt.Qt.AscendingOrder):
+#        if column == LEVEL:
+#            f = lambda a,b: cmp(a.levelno,b.levelno)
+#        elif column == TYPE:
+#            def f(a,b):
+#                if not operator.isMappingType(a) or not operator.isMappingType(b):
+#                    return 0
+#                return cmp(a.args.get('type','tau'), b.args.get('type','tau'))
+#        elif column == TIME:
+#            f = lambda a,b: cmp(a.created,b.created)
+#        elif column == MSG:
+#            f = lambda a,b: cmp(a.msg,b.msg)
+#        elif column == NAME:
+#            f = lambda a,b: cmp(a.name,b.name)
+#        elif column == THREAD:
+#            f = lambda a,b: cmp(a.threadName,b.threadName)
+#        elif column == LOCALT:
+#            f = lambda a,b: cmp(a.relativeCreated,b.relativeCreated)
+#        self._records = sorted(self._records, cmp=f,reverse= order == Qt.Qt.DescendingOrder)
+#        #self.reset()
+    
+    def rowCount(self, index=Qt.QModelIndex()):
+        return len(self._records)
+
+    def columnCount(self, index=Qt.QModelIndex()):
+        return len(HORIZ_HEADER)
+    
+    def data(self, index, role=Qt.Qt.DisplayRole):
+        if not index.isValid() or not (0 <= index.row() < len(self._records)):
+            return Qt.QVariant()
+        column, row = index.column(), index.row()
+        record = self._records[row]
+        if record.err:
+            err = PyTango.DevFailed(*record.errors)
+        else:
+            err = None
+        name = record.s_attr_name.lower()
+        if role == Qt.Qt.DisplayRole:
+            if column == ID:
+                return Qt.QVariant(row)
+            if column == HOST:
+                return Qt.QVariant(record.host)
+            elif column == DEVICE:
+                return Qt.QVariant(record.dev_name)
+            elif column == ATTRIBUTE:
+                return Qt.QVariant(record.s_attr_name)
+            elif column == VALUE:
+                if err is None:
+                    return Qt.QVariant(deviceAttributeValueStr(record.attr_value))
+                else:
+                    return Qt.QVariant(err[0].reason)
+            elif column == TIME:
+                if err is None:
+                    return Qt.QVariant(record.attr_value.time.strftime("%H:%M:%S.%f"))
+                else:
+                    return Qt.QVariant(record.reception_date.strftime("%H:%M:%S.%f"))
+        elif role == Qt.Qt.TextAlignmentRole:
+            if column in (HOST, DEVICE, ATTRIBUTE):
+                return Qt.QVariant(Qt.Qt.AlignLeft|Qt.Qt.AlignVCenter)
+            return Qt.QVariant(Qt.Qt.AlignRight|Qt.Qt.AlignVCenter)
+        elif role == Qt.Qt.BackgroundRole:
+            if column == VALUE:
+                if err is None:
+                    if name == "state":
+                        bg = getBrushForState(record.attr_value.value)[0]
+                    else:
+                        bg = getBrushForQuality(record.attr_value.quality)[0]
+                else:
+                    bg = Qt.QBrush(Qt.Qt.red)
+            else:
+                if index.row() % 2:
+                    bg = self.DftOddRowBrush[0]
+                else:
+                    bg = self.DftEvenRowBrush[0]
+            return Qt.QVariant(bg)
+        elif role == Qt.Qt.ForegroundRole:
+            if column == VALUE:
+                if err is None:
+                    if name == "state":
+                        fg = getBrushForState(record.attr_value.value)[1]
+                    else:
+                        fg = getBrushForQuality(record.attr_value.quality)[1]
+                else:
+                    fg = Qt.QBrush(Qt.Qt.white)
+            else:
+                if index.row() % 2:
+                    fg = self.DftOddRowBrush[1]
+                else:
+                    fg = self.DftEvenRowBrush[1]
+            return Qt.QVariant(fg)
+        elif role == Qt.Qt.ToolTipRole:
+            if err is None:
+                return Qt.QVariant(str(record.attr_value))
+            else:
+                return Qt.QVariant(str(record))
+        elif role == Qt.Qt.SizeHintRole:
+            return self._getSizeHint(column)
+        #elif role == Qt.Qt.StatusTipRole:
+        #elif role == Qt.Qt.CheckStateRole:
+        elif role == Qt.Qt.FontRole:
+            return Qt.QVariant(Qt.QFont("Mono", 8))
+        return Qt.QVariant()
+
+    def _getSizeHint(self, column):
+        return Qt.QVariant(EventLoggerTableModel.DftColSize[column])
+
+    def headerData(self, section, orientation, role=Qt.Qt.DisplayRole):
+        if role == Qt.Qt.TextAlignmentRole:
+            if orientation == Qt.Qt.Horizontal:
+                return Qt.QVariant(int(Qt.Qt.AlignLeft | Qt.Qt.AlignVCenter))
+            return Qt.QVariant(int(Qt.Qt.AlignRight | Qt.Qt.AlignVCenter))
+        elif role == Qt.Qt.SizeHintRole:
+            if orientation == Qt.Qt.Vertical:
+                return Qt.QVariant(Qt.QSize(50, 20))
+            else:
+                return self._getSizeHint(section)
+        elif role == Qt.Qt.FontRole:
+            return Qt.QVariant(Qt.QFont("Mono", 8))
+        elif role == Qt.Qt.ToolTipRole:
+            if section == HOST:
+                return Qt.QVariant("tango host")
+            elif section == DEVICE:
+                return Qt.QVariant("tango device")
+            elif section == ATTRIBUTE:
+                return Qt.QVariant("tango attribute")
+            elif section == VALUE:
+                return Qt.QVariant("attribute value")
+            elif section == TIME:
+                return Qt.QVariant("time stamp for the event")
+        if role != Qt.Qt.DisplayRole:
+            return Qt.QVariant()
+        if orientation == Qt.Qt.Horizontal:
+            return Qt.QVariant(HORIZ_HEADER[section])
+        return Qt.QVariant(int(section+1))
+    
+    def insertRows(self, position, rows=1, index=Qt.QModelIndex()):
+        self.beginInsertRows(Qt.QModelIndex(), position, position+rows-1)
+        self.endInsertRows()
+    
+    def removeRows(self, position, rows=1, index=Qt.QModelIndex()):
+        self.beginRemoveRows(Qt.QModelIndex(), position, position+rows-1)
+        self.endRemoveRows()
+
+    #def setData(self, index, value, role=Qt.Qt.DisplayRole):
+    #    pass
+    
+    #def flags(self, index)
+    #    pass
+        
+    #def insertColumns(self):
+    #    pass
+    
+    #def removeColumns(self):
+    #    pass
+    
+    # --------------------------
+    # logging.Handler overwrite
+    # --------------------------
+
+    def timerEvent(self, evt):
+        self.updatePendingRecords()
+
+    def updatePendingRecords(self):
+        if not self._accumulated_records:
+            return
+        row_nb = self.rowCount()
+        records = self._accumulated_records
+        self._accumulated_records = []
+        self._records.extend(records)
+        self.insertRows(row_nb, len(records))
+        if len(self._records) > self._capacity:
+            start = len(self._records) - self._capacity
+            self._records = self._records[start:]
+            self.removeRows(0, start)
+    
+    def push_event(self, evt):
+        attr_name = evt.attr_name
+        dev, sep, attr = attr_name.rpartition('/')
+        if dev.startswith("tango://"):
+            dev = dev[8:]
+        if dev.count(":"):
+            # if it has tango host
+            host, sep, dev = dev.partition('/')
+        else:
+            host = "-----"
+        evt.host = host
+        evt.dev_name = dev
+        evt.s_attr_name = attr
+        self._accumulated_records.append(evt)
+
+    def clearContents(self):
+        self.removeRows(0, self.rowCount())
+        self._records = []
+        self._accumulated_records = []
+
+    def getEvents(self):
+        return self._records
+    
+class EventLoggerTable(Qt.QTableView):
+    
+    DftScrollLock = False
+    
+    """A Qt table that displays the event logging messages"""
+    def __init__(self, parent=None, model=None, designMode=False):
+        super(EventLoggerTable, self).__init__(parent)
+        self.setShowGrid(False)
+        self.resetScrollLock()
+        model = model or EventLoggerTableModel()
+        self.setModel(model)
+        hh = self.horizontalHeader()
+        hh.setResizeMode(HOST, Qt.QHeaderView.Stretch)
+        self.setSortingEnabled(False)
+        #self.sortByColumn(TIME, Qt.Qt.AscendingOrder)
+
+    def rowsInserted(self, index, start, end):
+        """Overwrite of slot rows inserted to do proper resize and scroll to 
+        bottom if desired
+        """
+        for i in xrange(start,end+1):
+            self.resizeRowToContents(i)
+        if start == 0:
+            self.resizeColumnsToContents()
+        if not self._scrollLock:
+            self.scrollToBottom()
+
+    def setScrollLock(self, scrollLock):
+        """Sets the state for scrollLock"""
+        self._scrollLock = scrollLock
+    
+    def getScrollLock(self):
+        """Returns wheater or not the scrollLock is active"""
+        return self._scrollLock
+
+    def resetScrollLock(self):
+        self.setScrollLock(EventLoggerTable.DftScrollLock)
+
+    def clearContents(self):
+        self.model().clearContents()
+    
+    def getEvents(self):
+        return self.model().getEvents()
+
+    def sizeHint(self):
+        return Qt.QSize(700, 400)
+    
+    #: Tells wheater the table should scroll automatically to the end each
+    #: time a record is added or not
+    autoScroll = Qt.pyqtProperty("bool", getScrollLock, setScrollLock, resetScrollLock)
+
+
+class EventLoggerWidget(Qt.QWidget):
+    
+    def __init__(self, parent=None, model=None, designMode=False):
+        super(EventLoggerWidget, self).__init__(parent)
+        self._model = model or EventLoggerTableModel()
+        self.init(designMode)
+        
+    def init(self, designMode):
+        l = Qt.QGridLayout()
+        l.setContentsMargins(0,0,0,0)
+        l.setVerticalSpacing(2)
+        self.setLayout(l)
+        
+        table = self._logtable = EventLoggerTable(model = self._model, designMode=designMode)
+        tb = self._toolbar = Qt.QToolBar("Event logger toolbar")
+        tb.setFloatable(False)
+        
+        self._clearButton = Qt.QPushButton("Clear")
+        Qt.QObject.connect(self._clearButton, Qt.SIGNAL("clicked()"), table.clearContents)
+        tb.addWidget(self._clearButton)
+        l.addWidget(tb, 0, 0)
+        l.addWidget(table, 1, 0)
+        l.setColumnStretch(0,1)
+        l.setRowStretch(1,1)
+    
+    def model(self):
+        return self._model
+
+    def getEvents(self):
+        return self.model().getEvents()
+
+EventLogger = EventLoggerWidget
\ No newline at end of file
diff --git a/PyTango/ipython/ipython.py b/PyTango/ipython/ipython.py
new file mode 100644
index 0000000..077ca63
--- /dev/null
+++ b/PyTango/ipython/ipython.py
@@ -0,0 +1,64 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+try:
+    import IPython
+except:
+    IPython = None
+
+def get_ipython_version():
+    """Returns the current IPython version"""
+    if IPython is None:return None
+    v = None
+    try:
+        try:
+            v = IPython.Release.version
+        except Exception, e1:
+            try:
+                v = IPython.release.version
+            except Exception, e2:
+                pass
+    except Exception, e3:
+        pass
+    return v
+
+def default_init_ipython(ip, store=True, pytango=True, colors=True, console=True, magic=True):
+    print "Unsupported IPython version (%s) for spock profile" % get_ipython_version()
+    print "Supported IPython versions are: 0.10"
+    print "Starting normal IPython console..."
+
+def __define_init():
+    _ipv_str = get_ipython_version()
+
+    if _ipv_str is None:
+        _ipv = 0,0
+    else:
+        _ipv = tuple(map(int,_ipv_str.split(".")[:3]))
+
+    ret = default_init_ipython
+    if _ipv >= (0,10) and _ipv <= (0,11):
+        import ipython_00_10
+        ret = ipython_00_10.init_ipython
+    return ret
+
+init_ipython = __define_init()
+#init_ipython(IPython.ipapi.get())
diff --git a/PyTango/ipython/ipython_00_10.py b/PyTango/ipython/ipython_00_10.py
new file mode 100644
index 0000000..b1950d6
--- /dev/null
+++ b/PyTango/ipython/ipython_00_10.py
@@ -0,0 +1,978 @@
+#!/usr/bin/env python
+
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""An IPython profile designed to provide a user friendly interface to Tango"""
+
+import sys
+import os
+import token
+import tokenize
+import copy
+import re
+import operator
+import StringIO
+import textwrap
+import IPython.ipapi
+import IPython.ColorANSI
+import IPython.Prompts
+import IPython.PyColorize
+import IPython.excolors
+import IPython.ipstruct
+import IPython.genutils
+import PyTango
+import PyTango.utils
+
+_DB_SYMB = "db"
+_DFT_TANGO_HOST = None
+_SPOCK_STORE = "__spock_store"
+_SPOCK_ERR = "__spock_error"
+_spock_init = False
+
+class DeviceClassCompleter(object):
+    """Completer class that returns the list of devices of some class when
+    called. """
+    
+    def __init__(self, klass, devices):
+        self._klass = klass
+        self._devices = devices
+    
+    def __call__(self, ip, evt):
+        return self._devices
+
+
+# Rewrite DeviceProxy constructor because the database context that the user is
+# using may be different than the default TANGO_HOST. What we do is always append
+# the name of the database in usage to the device name given by the user (in case 
+# he doesn't give a database name him(her)self, of course.
+__DeviceProxy_init_orig__ = PyTango.DeviceProxy.__init__
+def __DeviceProxy__init__(self, dev_name):
+    db = __get_db()
+    if db is None: return
+    if dev_name.count(":") == 0:
+        db_name = "%s:%s" % (db.get_db_host(), db.get_db_port())
+        dev_name = "%s/%s" % (db_name, dev_name)
+    __DeviceProxy_init_orig__(self, dev_name)
+PyTango.DeviceProxy.__init__ = __DeviceProxy__init__
+
+#-------------------------------------------------------------------------------
+# Completers
+#-------------------------------------------------------------------------------
+
+def __DeviceProxy_completer(ip, evt):
+    db = __get_db()
+    if db is None: return
+    ret = db._db_cache.devices.keys()
+    ret.extend(db._db_cache.aliases.keys())
+    return ret
+
+def __DeviceClass_completer(ip, evt):
+    db = __get_db()
+    if db is None: return
+    return db._db_cache.klasses.keys()
+
+def __DeviceAlias_completer(ip, evt):
+    db = __get_db()
+    if db is None: return
+    return db._db_cache.aliases.keys()
+
+def __AttributeAlias_completer(ip, evt):
+    db = __get_db()
+    if db is None: return
+    return db._db_cache.attr_aliases.keys()
+
+def __PureDeviceProxy_completer(ip, evt):
+    db = __get_db()
+    if db is None: return
+    return db._db_cache.devices.keys()
+
+def __AttributeProxy_completer(ip, evt):
+    db = __get_db()
+    if db is None: return
+    cache = db._db_cache
+    
+    symb = evt.symbol
+    n = symb.count("/")
+    ret, devs, dev_aliases = None, cache.devices, cache.aliases
+    # dev_list and dev_alias_list are case insensitive. They should only be used
+    # to search for elements. Their elements are the same as the keys of the 
+    # dictionaries devs and dev_aliases respectively
+    dev_list, dev_alias_list = cache.device_list, cache.alias_list
+    dev_name = None
+    if n == 0:
+        # means it can be an attr alias, a device name has alias or as full device name
+        ret = cache.get("attr_aliases").keys()
+        ret.extend([ d+"/" for d in devs ])
+        ret.extend([ d+"/" for d in dev_aliases ])
+        # device alias found!
+        if symb in dev_alias_list:
+            dev_name = symb
+    elif n == 1:
+        # it can still be a full device name
+        ret = [ d+"/" for d in devs ]
+        # it can also be devalias/attr_name
+        dev, attr = symb.split("/")
+        if dev in dev_alias_list:
+            dev_name = dev
+    elif n == 2:
+        # it is for sure NOT an attribute alias or a device alias
+        ret = [ d+"/" for d in devs ]
+        # device found!
+        if symb in dev_list:
+            dev_name = symb
+    elif n == 3:
+        # it is for sure a full attribute name
+        dev, sep, attr = symb.rpartition("/")
+        if dev in dev_list:
+            dev_name = dev
+
+    if dev_name is None:
+        return ret
+    
+    try:
+        d = __get_device_proxy(dev_name)
+        # first check in cache for the attribute list
+        if not hasattr(d, "_attr_list"):
+            d._attr_list = d.get_attribute_list()
+        if ret is None:
+            ret = []
+        ret.extend([ "%s/%s" % (dev_name, a) for a in d._attr_list ])
+    except:
+        # either DeviceProxy could not be created or device is not online
+        pass
+
+    return ret
+
+def __get_device_proxy(dev_name):
+    db = __get_db()
+    if db is None: return
+    cache = db._db_cache
+    from_alias = cache.aliases.get(dev_name)
+    
+    if from_alias is not None:
+        dev_name = from_alias
+
+    data = cache.devices.get(dev_name)
+    if data is not None:
+        d = data[3]
+        if d is None:
+            try:
+                d = data[3] = PyTango.DeviceProxy(dev_name)
+            except:
+                pass
+        return d
+
+def __get_device_subscriptions(dev_name):
+    db = __get_db()
+    if db is None: return
+    cache = db._db_cache
+    from_alias = cache.aliases.get(dev_name)
+    
+    if from_alias is not None:
+        dev_name = from_alias
+
+    data = cache.devices.get(dev_name)
+    if data is not None:
+        return data[4]
+
+def __switchdb_completer(ip, evt):
+    return __get_store(ip, "database_list").keys()
+
+__monitor_completer = __AttributeProxy_completer
+
+#-------------------------------------------------------------------------------
+# Magic commands
+#-------------------------------------------------------------------------------
+
+def magic_refreshdb(self, parameter_s=''):
+    init_db(IPython.ipapi.get(), parameter_s)
+
+def magic_switchdb(self, parameter_s=''):
+    """Switches the active tango Database.
+    
+    Usage: switchdb <host>[(:| )<port>]
+
+    <port> is optional. If not given it defaults to 10000.
+    
+    Examples:
+    In [1]: switchdb homer:10005
+    In [2]: switchdb homer 10005
+    In [3]: switchdb homer"""
+    
+    if parameter_s == '':
+        raise IPython.ipapi.UsageError("%switchdb: Must specify a tango database name. See '%switchdb?'")
+    return init_db(IPython.ipapi.get(), parameter_s)
+
+def magic_lsdev(self, parameter_s=''):
+    """Lists all known tango devices.
+    
+    Usage: lsdev [<device name filter(regular expression)]
+    
+    Examples:
+    In [1]: lsdev
+    In [2]: lsdev sys.*"""
+    
+    if parameter_s:
+        reg_exp = re.compile(parameter_s, re.IGNORECASE)
+    else:
+        reg_exp = None
+    
+    db = __get_db()
+    if db is None:
+        print "You are not connected to any Tango Database. Device list is empty"
+        return
+    data = db._db_cache.devices
+
+    s = StringIO.StringIO()
+    cols = 40, 25, 25, 20
+    l = "%{0}s %{1}s %{2}s %{3}s".format(*cols)
+    print >>s, l % ("Device", "Alias", "Server", "Class")
+    print >>s, l % (cols[0]*"-", cols[1]*"-", cols[2]*"-", cols[3]*"-")
+    for d, v in data.items():
+        if reg_exp and not reg_exp.match(d): continue
+        print >>s, l % (d, v[0], v[1], v[2])
+    s.seek(0)
+    IPython.genutils.page(s.read())
+
+def magic_lsdevclass(self, parameter_s=''):
+    """Lists all known tango device classes.
+    
+    Usage: lsdevclass [<class name filter(regular expression)]
+    
+    Examples:
+    In [1]: lsdevclass
+    In [2]: lsdevclass Motor.*"""
+    
+    if parameter_s:
+        reg_exp = re.compile(parameter_s, re.IGNORECASE)
+    else:
+        reg_exp = None
+    
+    db = __get_db()
+    if db is None:
+        print "You are not connected to any Tango Database. Device class list is empty"
+        return
+    data = db._db_cache.klasses
+
+    s = StringIO.StringIO()
+    data = [ "%-030s" % klass for klass in data.keys() if not reg_exp or reg_exp.match(klass) ]
+    s = textwrap.fill(" ".join(data), 80)
+    IPython.genutils.page(s)
+
+def magic_lsserv(self, parameter_s=''):
+    """Lists all known tango servers.
+    
+    Usage: lsserv [<class name filter(regular expression)]
+    
+    Examples:
+    In [1]: lsserv
+    In [2]: lsserv Motor/.*"""
+    
+    if parameter_s:
+        reg_exp = re.compile(parameter_s, re.IGNORECASE)
+    else:
+        reg_exp = None
+    
+    db = __get_db()
+    if db is None:
+        print "You are not connected to any Tango Database. Device class list is empty"
+        return
+    data = db._db_cache.servers
+
+    s = StringIO.StringIO()
+    data = [ "%-030s" % server for server in data.keys() if not reg_exp or reg_exp.match(server) ]
+    s = textwrap.fill(" ".join(data), 80)
+    IPython.genutils.page(s)
+
+def magic_tango_error(self, parameter_s=''):
+    """Displays detailed information about the last tango error"""
+    
+    global _SPOCK_ERR
+    err_info = self.user_ns.get(_SPOCK_ERR)
+    if err_info is None:
+        print "No tango error reported so far."
+        return
+    print "Last tango error:"
+    print err_info[1]
+    
+_EVT_LOG = None
+def __get_event_log():
+    global _EVT_LOG
+    if _EVT_LOG is None:
+        qthreads = IPython.ipapi.get().options.q4thread
+        if qthreads:
+            import ipy_qt
+            model = ipy_qt.EventLoggerTableModel(capacity=10000)
+            _EVT_LOG = ipy_qt.EventLogger(model=model)
+            _EVT_LOG.setWindowTitle("Spock - Event Logger Table")
+        else:
+            import ipy_cli
+            _EVT_LOG = ipy_cli.EventLogger(capacity=10000)
+    return _EVT_LOG
+
+def magic_mon(self, parameter_s=''):
+    """Monitor a given attribute.
+    
+    %mon -a <attribute name>           - activates monitoring of given attribute
+    %mon -d <attribute name>           - deactivates monitoring of given attribute
+    %mon -r                            - deactivates monitoring of all attributes
+    %mon -i <id>                       - displays detailed information for the event with given id
+    %mon -l <dev filter> <attr filter> - shows event table filtered with the regular expression for attribute name
+    %mon                               - shows event table (= %mon -i .* .*)"""
+    
+    db = __get_db()
+    if db is None:
+        print "You are not connected to any Tango Database."
+        return
+    opts, args = self.parse_options(parameter_s,'adril', mode='list')
+    if len(args) > 3:
+        raise IPython.ipapi.UsageError("%mon: too many arguments")
+    if opts.has_key('d'):
+        try:
+            todel = args[0]
+        except IndexError:
+            raise IPython.ipapi.UsageError(
+                "%mon -d: must provide an attribute to unmonitor")
+        else:
+            try:
+                dev, sep, attr = todel.rpartition("/")
+                subscriptions = __get_device_subscriptions(dev)
+                id = subscriptions[attr.lower()]
+                del subscriptions[attr.lower()]
+                d = __get_device_proxy(dev)
+                d.unsubscribe_event(id)
+                print "Stopped monitoring '%s'" % todel
+            except KeyError:
+                raise IPython.ipapi.UsageError(
+                    "%%mon -d: Not monitoring '%s'" % todel)
+                    
+    elif opts.has_key('a'):
+        try:
+            toadd = args[0]
+        except IndexError:
+            raise IPython.ipapi.UsageError(
+                "%mon -a: must provide an attribute to monitor")
+        dev, sep, attr = toadd.rpartition("/")
+        subscriptions = __get_device_subscriptions(dev)
+        id = subscriptions.get(attr.lower())
+        if id is not None:
+            raise IPython.ipapi.UsageError(
+                "%%mon -a: Already monitoring '%s'" % toadd)
+        d = __get_device_proxy(dev)
+        w = __get_event_log()
+        model = w.model()
+        id = d.subscribe_event(attr, PyTango.EventType.CHANGE_EVENT, model, [])
+        subscriptions[attr.lower()] = id
+        print "'%s' is now being monitored. Type 'mon' to see all events" % toadd
+    elif opts.has_key('r'):
+        for d, v in db._db_cache.devices.items():
+            d, subs = v[3], v[4]
+            for id in subs.values():
+                d.unsubscribe_event(id)
+            v[4] = {}
+    elif opts.has_key('i'):
+        try:
+            evtid = int(args[0])
+        except IndexError:
+            raise IPython.ipapi.UsageError(
+                "%mon -i: must provide an event ID")
+        except ValueError:
+            raise IPython.ipapi.UsageError(
+                "%mon -i: must provide a valid event ID")
+        try:
+            w = __get_event_log()
+            e = w.getEvents()[evtid]
+            if e.err:
+                print str(PyTango.DevFailed(*e.errors))
+            else:
+                print str(e)
+        except IndexError:
+            raise IPython.ipapi.UsageError(
+                "%mon -i: must provide a valid event ID")
+    elif opts.has_key('l'):
+        try:
+            dexpr = args[0]
+            aexpr = args[1]
+        except IndexError:
+            raise IPython.ipapi.UsageError(
+                "%mon -l: must provide valid device and attribute filters")
+        w = __get_event_log()
+        w.show(dexpr, aexpr)
+    else:
+        w = __get_event_log()
+        w.show()
+
+#-------------------------------------------------------------------------------
+# Useful functions (not magic commands but accessible from CLI as normal python
+# functions)
+#-------------------------------------------------------------------------------
+
+def get_device_map():
+    """Returns a dictionary where keys are device names and value is a sequence
+    of 4 elements: 
+        - alias name (empty string if no alias is defined)
+        - tango server name (full tango server name <name>/<instance>)
+        - tango class name
+        - DeviceProxy to the device or None if it hasn't been initialized yet
+          (this last element is for internal spock usage only. If you need a 
+           DeviceProxy to this device, create your own)"""
+    db = __get_db()
+    if db is None:
+        print "You are not connected to any Tango Database."
+        return
+    return db._db_cache.devices
+
+def get_server_map():
+    """Returns a dictionary where keys are server names (<name>/<instance>)
+    and value is a sequence of device names that belong to the server"""
+    db = __get_db()
+    if db is None:
+        print "You are not connected to any Tango Database."
+        return
+    return db._db_cache.servers
+
+def get_class_map():
+    """Returns a dictionary where keys are the tango classes and value is a 
+    sequence of device names that belong to the tango class"""
+    db = __get_db()
+    if db is None:
+        print "You are not connected to any Tango Database."
+        return
+    return db._db_cache.klasses
+
+def get_alias_map():
+    """Returns a dictionary where keys are the tango device aliases and value 
+    is a the tango device name"""
+    db = __get_db()
+    if db is None:
+        print "You are not connected to any Tango Database."
+        return
+    return db._db_cache.aliases
+
+def get_device_list():
+    """Returns a case insensitive list of device names for the current 
+    database"""
+    db = __get_db()
+    if db is None:
+        print "You are not connected to any Tango Database."
+        return
+    return db._db_cache.device_list
+
+def get_alias_list():
+    """Returns a case insensitive list of device aliases for the current 
+    database"""
+    db = __get_db()
+    if db is None:
+        print "You are not connected to any Tango Database."
+        return
+    return db._db_cache.alias_list    
+    
+#-------------------------------------------------------------------------------
+# Private helper methods
+#-------------------------------------------------------------------------------
+
+def __tango_exc_handler(ip, etype, value, tb):
+    global _SPOCK_ERR
+    ip.user_ns[_SPOCK_ERR] = etype, value, tb
+    if etype == PyTango.DevFailed:
+        v = value[0]
+        print v.reason,":",v.desc
+        print "For more detailed information type: tango_error"
+        
+def __safe_tango_exec(f, *args, **kwargs):
+    try:
+        return f(*args, **kwargs)
+    except PyTango.DevFailed, df:
+        print df[0].reason,":",df[0].desc
+        print "For more information type: get_last_tango_error"
+
+def __get_default_tango_host():
+    global _DFT_TANGO_HOST
+    if _DFT_TANGO_HOST is None:
+        _DFT_TANGO_HOST = os.environ.get("TANGO_HOST")
+        if _DFT_TANGO_HOST is None:
+            # ok, it must have been defined in the tangorc way. Since the
+            # method Tango::Connection::get_env_var is protected we do a hack to
+            # get the tango_host: Create a temporary Database object. It is not
+            #very nice but is done only once in the lifetime of the application 
+            try:
+                db = PyTango.Database()
+                _DFT_TANGO_HOST = "%s:%s" % (db.get_db_host(), db.get_db_port())
+            except:
+                pass
+    return _DFT_TANGO_HOST
+
+def __get_db(host_port=None):
+    """host_port == None: Use current DB whatever it is or create
+                          default if doesn't exist
+       host_port == '' : use default db. If it is not the current db, switch
+                         current db to it and return it
+       host_port == ... : if ... is not the current db, switch current db to it
+                          and return it
+    """
+    
+    ip = IPython.ipapi.get()
+    global _DB_SYMB
+    db = ip.user_ns.get(_DB_SYMB)
+    
+    if host_port is None:
+        if db is None:
+            host_port = __get_default_tango_host()
+    elif host_port == '':
+        host_port = __get_default_tango_host()
+    else:
+        host_port = host_port.strip().replace(" ",":")
+        if host_port.count(":") == 0:
+            host_port += ":10000"
+        
+    if db is None:
+        create_db = True
+    elif host_port is None:
+        create_db = False
+    else:
+        old_host_port = "%s:%s" % (db.get_db_host(), db.get_db_port())
+        create_db = old_host_port != host_port
+
+    if create_db:
+        try:
+            db = PyTango.Database(*host_port.split(":"))
+            
+            ip.user_ns["DB_NAME"] = host_port
+        except Exception, e:
+            print 
+            if db:
+                print "Could not access Database", host_port
+                old_host_port = "%s:%s" % (db.get_db_host(), db.get_db_port())
+                print "Maintaining connection to Database", old_host_port
+                ip.user_ns["DB_NAME"] = old_host_port
+            else:
+                print "Could not access any Database."
+                print "Make sure .tangorc, /etc/tangorc or TANGO_HOST environment is defined."
+                ip.user_ns["DB_NAME"] = "OFFLINE"
+                
+        # register the 'db' in the user namespace
+        ip.to_user_ns({ _DB_SYMB : db })
+        
+    return db
+
+def __get_obj_name(o):
+    try:
+        n = o.__name__
+    except:
+        try:
+            n = o.__class__.__name__
+        except:
+            n = "<unknown>"
+    return n
+
+def __completer_wrapper(f):
+    def wrapper(ip, evt):
+        try:
+            return f(ip, evt)
+        except Exception, e:
+            print
+            print "An unexpected exception ocorred during Spock command completer."
+            print "Please send a bug report to the PyTango team with the following informantion:"
+            print IPython.ipapi.get().options.banner
+            print 80*"-"
+            print "Completer:",__get_obj_name(f)
+            print 80*"-"
+            print str(e)
+            print 80*"-"
+            raise e
+    return wrapper
+
+def __get_python_version():
+    return '.'.join(map(str,sys.version_info[:3]))
+
+def __get_ipython_version():
+    """Returns the current IPython version"""
+    v = None
+    try:
+        try:
+            v = IPython.Release.version
+        except Exception, e1:
+            try:
+                v = IPython.release.version
+            except Exception, e2:
+                pass
+    except Exception, e3:
+        pass
+    return v
+
+def __get_pytango_version():
+    vi = PyTango.Release.version_info
+    return ".".join(map(str,vi[:3]))+vi[3]
+
+def __get_ipapi():
+    return IPython.ipapi.get()
+
+def __expose_magic(ip, name, fn, completer_func=None):
+    ip.expose_magic(name, fn)
+    
+    if completer_func is None:
+        return
+    
+    # enable macro param completion
+    ip.set_hook('complete_command', completer_func, re_key = ".*" + name)
+
+def __unexpose_magic(ip, name):
+    mg = 'magic_%s' % name
+    delattr(ip.IP, mg)
+
+def __build_color_scheme(ip, name):
+    
+    # make some schemes as instances so we can copy them for modification easily:
+    ColorANSI = IPython.ColorANSI
+    ColorScheme = ColorANSI.ColorScheme
+    InputColors = ColorANSI.InputTermColors
+    TermColors = ColorANSI.TermColors
+    PromptColors = IPython.Prompts.PromptColors
+    ANSICodeColors = IPython.PyColorize.ANSICodeColors
+    ExceptionColors = IPython.excolors.ExceptionColors
+    TBColors = ip.IP.InteractiveTB.color_scheme_table
+    SyntaxColors = ip.IP.SyntaxTB.color_scheme_table
+    InspectColors = IPython.OInspect.InspectColors
+    
+    promptTangoColors = PromptColors['Linux'].copy(name)
+    ANSITangoColors = ANSICodeColors['Linux'].copy(name)
+    exceptionTangoColors = ExceptionColors['Linux'].copy(name)
+    TBTangoColors = TBColors['Linux'].copy(name)
+    syntaxTangoColors = SyntaxColors['Linux'].copy(name)
+    inspectTangoColors = InspectColors['Linux'].copy(name)
+    
+    # initialize prompt with default tango colors
+    promptTangoColors.colors.in_prompt  = InputColors.Purple
+    promptTangoColors.colors.in_number  = InputColors.LightPurple
+    promptTangoColors.colors.in_prompt2 = InputColors.Purple
+    promptTangoColors.colors.out_prompt = TermColors.Blue
+    promptTangoColors.colors.out_number = TermColors.LightBlue
+
+    ret= { "prompt" : (PromptColors, promptTangoColors),
+          "ANSI"   : (ANSICodeColors, ANSITangoColors),
+          "except" : (ExceptionColors, exceptionTangoColors),
+          "TB"     : (TBColors, TBTangoColors),
+          "Syntax" : (SyntaxColors, syntaxTangoColors),
+          "Inspect": (InspectColors, inspectTangoColors) }
+
+    if ip.IP.isthreaded:
+        TBThreadedColors = ip.IP.sys_excepthook.color_scheme_table
+        TBThreadedTangoColors = TBThreadedColors['Linux'].copy(name)
+        ret["TBThreaded"] = TBThreadedColors, TBThreadedTangoColors
+    return ret
+
+def __set_store(ip, key=None, value=None):
+    if key is not None:
+        spock_store = ip.user_ns.get(_SPOCK_STORE)
+        spock_store[key] = value
+    __store(ip, _SPOCK_STORE)
+
+def __get_store(ip, key, nvalue=None):
+    spock_store = ip.user_ns.get(_SPOCK_STORE)
+    v = spock_store.get(key)
+    if v is None and nvalue is not None:
+        spock_store[key] = nvalue
+        v = nvalue
+    return v
+
+def __store(ip, var):
+    # this executes the magic command store which prints a lot of info. So, first
+    # we hide the standard output 
+    stdout = sys.stdout
+    try:
+        sys.stdout = StringIO.StringIO()
+        ip.magic("store %s" % var)
+    finally:
+        sys.stdout = stdout
+        
+#-------------------------------------------------------------------------------
+# Initialization methods
+#-------------------------------------------------------------------------------
+
+def init_colors(ip):
+    ColorANSI = IPython.ColorANSI
+    ColorScheme = ColorANSI.ColorScheme
+    InputColors = ColorANSI.InputTermColors
+    TermColors = ColorANSI.TermColors
+    
+    name = "Tango"
+    scheme = __build_color_scheme(ip, name)
+    for k, v in scheme.items():
+        v[0].add_scheme(v[1])
+
+    name = "PurpleTango"
+    scheme = __build_color_scheme(ip, name)
+    for k, v in scheme.items():
+        v[0].add_scheme(v[1])
+
+    name = "BlueTango"
+    scheme = __build_color_scheme(ip, name)
+    prompt = scheme["prompt"][1]
+    prompt.colors.in_prompt  = InputColors.Blue
+    prompt.colors.in_number  = InputColors.LightBlue
+    prompt.colors.in_prompt2 = InputColors.Blue
+    prompt.colors.out_prompt = TermColors.Cyan
+    prompt.colors.out_number = TermColors.LightCyan
+    for k, v in scheme.items():
+        v[0].add_scheme(v[1])
+
+    name = "GreenTango"
+    scheme = __build_color_scheme(ip, name)
+    prompt = scheme["prompt"][1]
+    prompt.colors.in_prompt  = InputColors.Green
+    prompt.colors.in_number  = InputColors.LightGreen
+    prompt.colors.in_prompt2 = InputColors.Green
+    prompt.colors.out_prompt = TermColors.Red
+    prompt.colors.out_number = TermColors.LightRed
+    for k, v in scheme.items():
+        v[0].add_scheme(v[1])
+
+def init_pytango(ip):
+    """Initializes the IPython environment with PyTango elements"""
+    TermColors = IPython.ColorANSI.TermColors
+
+    # export symbols to IPython namepspace
+    ip.ex("import PyTango")
+    ip.ex("from PyTango import DeviceProxy, AttributeProxy, Database, Group")
+    ip.ex("Device = DeviceProxy")
+    ip.ex("Attribute = AttributeProxy")
+
+    # add completers
+    dp_completer = __completer_wrapper(__DeviceProxy_completer)
+    attr_completer = __completer_wrapper(__AttributeProxy_completer)
+    ip.set_hook('complete_command', dp_completer, re_key = ".*DeviceProxy[^\w\.]+")
+    ip.set_hook('complete_command', dp_completer, re_key = ".*Device[^\w\.]+")
+    ip.set_hook('complete_command', attr_completer, re_key = ".*AttributeProxy[^\w\.]+")
+    ip.set_hook('complete_command', attr_completer, re_key = ".*Attribute[^\w\.]+")
+    
+    ip.set_custom_exc((PyTango.DevFailed,), __tango_exc_handler)
+
+def init_db(ip, parameter_s=''):
+    global _DB_SYMB
+    old_db = ip.user_ns.get(_DB_SYMB)
+    
+    db = __get_db(parameter_s)
+    
+    if old_db is not None and hasattr(old_db, "_db_cache"):
+        old_junk = old_db._db_cache["junk"].keys()
+        for e in old_junk:
+            del ip.user_ns[e]
+    else:
+        old_junk = ()
+        
+    if db is None: return
+    
+    # Initialize device and server information
+    query = "SELECT name, alias, server, class FROM device order by name"
+    
+    r = db.command_inout("DbMySqlSelect", query)
+    row_nb, column_nb = r[0][-2], r[0][-1]
+    results, data = r[0][:-2], r[1]
+    assert row_nb == len(data) / column_nb
+    devices, aliases, servers, klasses = data[0::4], data[1::4], data[2::4], data[3::4]
+
+    #CD = PyTango.utils.CaselessDict
+    CD = dict
+    dev_dict, serv_dict, klass_dict, alias_dict = CD(), CD(), CD(), CD()
+    
+    for device, alias, server, klass in zip(devices, aliases, servers, klasses):
+        dev_lower = device.lower()
+
+        # hide dserver devices
+        if dev_lower.startswith("dserver/"): continue
+        
+        # hide alias that start with "_"
+        if alias and alias[0] == "_": alias = ''
+        
+        # last None below is to be filled by DeviceProxy object on demand
+        # last empty dict<str, int> where keys is attribute name and value is 
+        # the subscription id
+        dev_dict[device] = [alias, server, klass, None, {}]
+        serv_devs = serv_dict.get(server)
+        if serv_devs is None:
+            serv_dict[server] = serv_devs = []
+        serv_devs.append(device)
+        klass_devs = klass_dict.get(klass)
+        if klass_devs is None:
+            klass_dict[klass] = klass_devs = []
+        klass_devs.append(device)
+        if len(alias):
+            alias_dict[alias] = device
+            serv_devs.append(alias)
+            klass_devs.append(alias)
+
+    exposed_klasses = {}
+    excluded_klasses = "DServer",
+    for klass, devices in klass_dict.items():
+        if klass in excluded_klasses: continue
+        if not ip.user_ns.has_key(klass) or klass in old_junk:
+            c = DeviceClassCompleter(klass, devices)
+            ip.set_hook('complete_command', c, re_key = ".*" + klass + "[^\w\.]+")
+            exposed_klasses[klass] = PyTango.DeviceProxy
+        else:
+            print "Failed to add completer for DeviceClass",klass
+    
+    # expose classes no user namespace
+    ip.to_user_ns(exposed_klasses)
+    
+    # Initialize attribute information
+    query = "SELECT name, alias FROM attribute_alias order by alias"
+
+    r = db.command_inout("DbMySqlSelect", query)
+    row_nb, column_nb = r[0][-2], r[0][-1]
+    results, data = r[0][:-2], r[1]
+    assert row_nb == len(data) / column_nb
+    attributes, aliases = data[0::2], data[1::2]
+    
+    attr_alias_dict = {}
+    for attribute, alias in zip(attributes, aliases):
+        if len(alias):
+            attr_alias_dict[alias] = attribute
+    
+    device_list = PyTango.utils.CaselessList(dev_dict.keys())
+    alias_list = PyTango.utils.CaselessList(alias_dict.keys())
+    attr_alias_list = PyTango.utils.CaselessList(attr_alias_dict.keys())
+    
+    # Build cache
+    db_cache = IPython.ipstruct.Struct(devices=dev_dict, aliases=alias_dict,
+                                       servers=serv_dict, klasses=klass_dict,
+                                       junk=exposed_klasses,
+                                       attr_aliases=attr_alias_dict,
+                                       device_list=device_list,
+                                       alias_list=alias_list,
+                                       attr_alias_list=attr_alias_list)
+    
+    db._db_cache = db_cache
+
+    # Add this DB to the list of known DBs (for possible use in magic commands)
+    valid_dbs = __get_store(ip, "database_list", {})
+    if db.get_db_port_num() == 10000:
+        db_name = db.get_db_host()
+    else:
+        db_name = "%s:%s" % (db.get_db_host(), db.get_db_port())
+    valid_dbs[db_name] = None
+    __set_store(ip)
+    
+    return db
+
+def init_store(ip):
+    # recover the environment
+    ip.magic("store -r")
+    spock_store = ip.user_ns.get(_SPOCK_STORE)
+    
+    if spock_store is None:
+        print "Initializing spock store (should only happen once)"
+        spock_store = {}
+        ip.to_user_ns( { _SPOCK_STORE : spock_store} )
+        __store(ip, _SPOCK_STORE)
+        
+def init_console(ip):
+    
+    TermColors = IPython.ColorANSI.TermColors
+    
+    d = { "version" : PyTango.Release.version,
+          "pyver" : __get_python_version(),
+          "ipyver" : __get_ipython_version(),
+          "pytangover" : __get_pytango_version() }
+    d.update(TermColors.__dict__)
+
+    o = ip.options
+
+    so = IPython.ipstruct.Struct(
+        spock_banner = """{Blue}hint: Try typing: mydev = Device("{LightBlue}<tab>{Normal}\n""")
+
+    so = ip.user_ns.get("spock_options", so)
+    
+    o.colors = "Tango"
+    o.prompt_in1 = "Spock <$DB_NAME> [\\#]: "
+    o.prompt_out = "Result [\\#]: "
+    banner = """
+{LightPurple}Spock {version}{Normal} -- An interactive {Purple}Tango{Normal} client.
+
+Running on top of Python {pyver}, IPython {ipyver} and PyTango {pytangover}
+
+help      -> Spock's help system.
+object?   -> Details about 'object'. ?object also works, ?? prints more.
+
+""" + so.spock_banner
+    o.banner = banner.format(**d)
+    
+def init_magic(ip):
+    __expose_magic(ip, "refreshdb", magic_refreshdb)
+    __expose_magic(ip, "reloaddb", magic_refreshdb)
+    __expose_magic(ip, "switchdb", magic_switchdb, __switchdb_completer)
+    __expose_magic(ip, "lsdev", magic_lsdev)
+    __expose_magic(ip, "lsdevclass", magic_lsdevclass)
+    __expose_magic(ip, "lsserv", magic_lsserv)
+    __expose_magic(ip, "tango_error", magic_tango_error)
+    __expose_magic(ip, "mon", magic_mon, __monitor_completer)
+    #__expose_magic(ip, "umon", magic_umon, __monitor_completer)
+    
+    ip.to_user_ns({"get_device_map"   : get_device_map,
+                   "get_server_map"  : get_server_map,
+                   "get_class_map"   : get_class_map,
+                   "get_alias_map"   : get_alias_map,
+                   "get_device_list" : get_device_list,
+                   "get_alias_list"  : get_alias_list})
+    
+    #__expose_magic(ip, "get_device_map", get_device_map)
+    #__expose_magic(ip, "get_server_map", get_server_map)
+    #__expose_magic(ip, "get_class_map", get_class_map)
+    #__expose_magic(ip, "get_alias_map", get_alias_map)
+    #__expose_magic(ip, "get_device_list", get_device_list)
+    #__expose_magic(ip, "get_alias_list", get_alias_list)
+
+def complete(text):
+    """a super complete!!!!"""
+    self = IPython.ipapi.get().IP
+    complete = self.Completer.complete
+    state = 0
+    comps = set()
+    while True:
+        newcomp = complete("", state, line_buffer=text)
+        if newcomp is None:
+            break
+        comps.add(newcomp)
+        state += 1
+    outcomps = sorted(comps)
+    return outcomps
+
+def init_ipython(ip, store=True, pytango=True, colors=True, console=True, magic=True):
+    
+    if ip is None:
+        raise Exception("Spock's init_ipython must be called from inside IPython")
+    
+    global _spock_init
+    if _spock_init is True: return
+    
+    #ip.IP._orig_complete = ip.IP.complete
+    #ip.IP.complete = complete
+    
+    if colors:  init_colors(ip)
+    if store:   init_store(ip)
+    if pytango: init_pytango(ip)
+    init_db(ip)
+    if console: init_console(ip)
+    if magic:   init_magic(ip)
+    
+    _spock_init = True
diff --git a/PyTango/log4tango.py b/PyTango/log4tango.py
new file mode 100644
index 0000000..4a7618e
--- /dev/null
+++ b/PyTango/log4tango.py
@@ -0,0 +1,284 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module. It provides tango log classes that can
+be used as decorators in any method of :class:`PyTango.DeviceImpl`.
+
+To access these members use directly :mod:`PyTango` module and NOT PyTango.log4tango.
+
+Example::
+
+    import PyTango
+    
+    class MyDev(PyTango.Device_4Impl):
+        
+        PyTango.InfoIt()
+        def read_Current(self, attr):
+            attr.set_value(self._current)
+"""
+
+__all__ = [ "TangoStream", "LogIt", "DebugIt", "InfoIt", "WarnIt", 
+            "ErrorIt", "FatalIt" ]
+            
+__docformat__ = "restructuredtext"
+
+import functools
+
+class TangoStream:
+    
+    def __init__(self, fn):
+        self._fn = fn
+        self._accum = ""
+
+    def write(self, s):
+        self._accum += s
+        # while there is no new line, just accumulate the buffer
+        try:
+            if s[-1] == '\n' or s.index('\n') >= 0:
+                self.flush()
+        except ValueError:
+            pass
+        
+    def flush(self):
+        b = self._accum
+        if b is None or len(self._accum) == 0:
+            return
+        #take the '\n' because the log adds it
+        if b[-1] == '\n': b = b[:-1]
+        self._fn(b)
+        self._accum = ""
+
+
+class LogIt(object):
+    """A class designed to be a decorator of any method of a 
+    :class:`PyTango.DeviceImpl` subclass. The idea is to log the entrance and 
+    exit of any decorated method.
+
+    Example::
+    
+        class MyDevice(PyTango.Device_4Impl):
+            
+            @PyTango.LogIt()
+            def read_Current(self, attr):
+                attr.set_value(self._current, 1)
+
+    All log messages generated by this class have DEBUG level. If you whish
+    to have different log level messages, you should implement subclasses that
+    log to those levels. See, for example, :class:`PyTango.InfoIt`.
+
+    The constructor receives three optional arguments:
+        * show_args - shows method arguments in log message (defaults to False)
+        * show_kwargs - shows keyword method arguments in log message (defaults to False)
+        * show_ret - shows return value in log message (defaults to False)
+    """
+    
+    def __init__(self, show_args=False, show_kwargs=False, show_ret=False):
+        """Initializes de LogIt object.
+            
+            :param show_args: (bool) show arguments in log message (default is False)
+            :param show_kwargs: (bool) show keyword arguments in log message (default is False)
+            :param show_ret: (bool) show return in log message (default is False)
+        """
+        self._show_args = show_args
+        self._show_kwargs = show_kwargs
+        self._show_ret = show_ret
+
+    def __compact(self, v, maxlen=25):
+        v = repr(v)
+        if len(v) > maxlen:
+            v = v[:maxlen-6] + " [...]"
+        return v
+
+    def __compact_dict(self, k, v, maxlen=None):
+        if maxlen is None:
+            return "%s=%s" % (k, __compact(v))
+        return "%s=%s" % (k, __compact(v, maxlen=maxlen))
+
+    def is_enabled(self, d):
+        return d.get_logger().is_debug_enabled()
+
+    def get_log_func(self, d):
+        return d.debug_stream
+
+    def __call__(self, f):
+        @functools.wraps(f)
+        def log_stream(*args, **kwargs):
+            d = args[0]
+            if not self.is_enabled(d):
+                return f(*args, **kwargs)
+            in_msg = "-> %s(" % f.func_name
+            if self._show_args:
+                in_msg += ", ".join(map(self.__compact, args[1:]))
+            if self._show_kwargs:
+                kwargs_str = ( self.__compact_dict(k,v) for k,v in kwargs.items() )
+                in_msg += ", ".join(kwargs_str)
+            in_msg += ")"
+            self.get_log_func(d)(in_msg)
+            ret = f(*args, **kwargs)
+            out_msg = ""
+            if self._show_ret:
+                out_msg += self.__compact(ret) + " "
+            out_msg += "<- %s()" % f.func_name
+            self.get_log_func(d)(out_msg)
+            return ret
+        return log_stream
+
+
+class DebugIt(LogIt):
+    """A class designed to be a decorator of any method of a 
+    :class:`PyTango.DeviceImpl` subclass. The idea is to log the entrance and 
+    exit of any decorated method as DEBUG level records.
+
+    Example::
+    
+        class MyDevice(PyTango.Device_4Impl):
+            
+            @PyTango.DebugIt()
+            def read_Current(self, attr):
+                attr.set_value(self._current, 1)
+
+    All log messages generated by this class have DEBUG level.
+
+    The constructor receives three optional arguments:
+        * show_args - shows method arguments in log message (defaults to False)
+        * show_kwargs - shows keyword method arguments in log message (defaults to False)
+        * show_ret - shows return value in log message (defaults to False)
+    """
+
+    def is_enabled(self, d):
+        return d.get_logger().is_debug_enabled()
+
+    def get_log_func(self, d):
+        return d.debug_stream
+
+
+class InfoIt(LogIt):
+    """A class designed to be a decorator of any method of a 
+    :class:`PyTango.DeviceImpl` subclass. The idea is to log the entrance and 
+    exit of any decorated method as INFO level records.
+
+    Example::
+    
+        class MyDevice(PyTango.Device_4Impl):
+            
+            @PyTango.InfoIt()
+            def read_Current(self, attr):
+                attr.set_value(self._current, 1)
+
+    All log messages generated by this class have INFO level.
+    
+    The constructor receives three optional arguments:
+        * show_args - shows method arguments in log message (defaults to False)
+        * show_kwargs - shows keyword method arguments in log message (defaults to False)
+        * show_ret - shows return value in log message (defaults to False)
+    """
+
+    def is_enabled(self, d):
+        return d.get_logger().is_info_enabled()
+
+    def get_log_func(self, d):
+        return d.info_stream
+
+
+class WarnIt(LogIt):
+    """A class designed to be a decorator of any method of a 
+    :class:`PyTango.DeviceImpl` subclass. The idea is to log the entrance and 
+    exit of any decorated method as WARN level records.
+
+    Example::
+    
+        class MyDevice(PyTango.Device_4Impl):
+            
+            @PyTango.WarnIt()
+            def read_Current(self, attr):
+                attr.set_value(self._current, 1)
+
+    All log messages generated by this class have WARN level.
+
+    The constructor receives three optional arguments:
+        * show_args - shows method arguments in log message (defaults to False)
+        * show_kwargs - shows keyword method arguments in log message (defaults to False)
+        * show_ret - shows return value in log message (defaults to False)
+    """
+    
+    def is_enabled(self, d):
+        return d.get_logger().is_warn_enabled()
+
+    def get_log_func(self, d):
+        return d.warn_stream
+
+
+class ErrorIt(LogIt):
+    """A class designed to be a decorator of any method of a 
+    :class:`PyTango.DeviceImpl` subclass. The idea is to log the entrance and 
+    exit of any decorated method as ERROR level records.
+
+    Example::
+    
+        class MyDevice(PyTango.Device_4Impl):
+            
+            @PyTango.ErrorIt()
+            def read_Current(self, attr):
+                attr.set_value(self._current, 1)
+
+    All log messages generated by this class have ERROR level.
+
+    The constructor receives three optional arguments:
+        * show_args - shows method arguments in log message (defaults to False)
+        * show_kwargs - shows keyword method arguments in log message (defaults to False)
+        * show_ret - shows return value in log message (defaults to False)
+    """
+    
+    def is_enabled(self, d):
+        return d.get_logger().is_error_enabled()
+
+    def get_log_func(self, d):
+        return d.error_stream
+
+
+class FatalIt(LogIt):
+    """A class designed to be a decorator of any method of a 
+    :class:`PyTango.DeviceImpl` subclass. The idea is to log the entrance and 
+    exit of any decorated method as FATAL level records.
+
+    Example::
+    
+        class MyDevice(PyTango.Device_4Impl):
+            
+            @PyTango.FatalIt()
+            def read_Current(self, attr):
+                attr.set_value(self._current, 1)
+
+    All log messages generated by this class have FATAL level.
+
+    The constructor receives three optional arguments:
+        * show_args - shows method arguments in log message (defaults to False)
+        * show_kwargs - shows keyword method arguments in log message (defaults to False)
+        * show_ret - shows return value in log message (defaults to False)
+    """
+    
+    def is_enabled(self, d):
+        return d.get_logger().is_fatal_enabled()
+
+    def get_log_func(self, d):
+        return d.fatal_stream
\ No newline at end of file
diff --git a/PyTango/pytango_init.py b/PyTango/pytango_init.py
new file mode 100644
index 0000000..7603870
--- /dev/null
+++ b/PyTango/pytango_init.py
@@ -0,0 +1,81 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = []
+
+__docformat__ = "restructuredtext"
+
+import attribute_proxy
+import base_types
+import callback
+import api_util
+import connection
+import db
+import device_attribute
+import device_class
+import device_data
+import device_proxy
+import device_server
+import group
+import group_reply
+import group_reply_list
+import pytango_pprint
+import pyutil
+import time_val
+
+__INITIALIZED = False
+__DOC = True
+
+def __init():
+    global __INITIALIZED
+    if __INITIALIZED:
+        return
+    
+    global __DOC
+    doc = __DOC
+    base_types.init(doc=doc)
+    callback.init(doc=doc)
+    api_util.init(doc=doc)
+    connection.init(doc=doc)
+    db.init(doc=doc)
+    device_attribute.init(doc=doc)
+    device_class.init(doc=doc)
+    device_data.init(doc=doc)
+    device_proxy.init(doc=doc)
+    device_server.init(doc=doc)
+    group.init(doc=doc)
+    group_reply.init(doc=doc)
+    group_reply_list.init(doc=doc)
+    pytango_pprint.init(doc=doc)
+    pyutil.init(doc=doc)
+    time_val.init(doc=doc)
+    
+    # must come last: depends on device_proxy.init()
+    attribute_proxy.init(doc=doc)
+
+    __INITIALIZED = True
+    
+__init()
\ No newline at end of file
diff --git a/PyTango/pytango_pprint.py b/PyTango/pytango_pprint.py
new file mode 100644
index 0000000..3acd798
--- /dev/null
+++ b/PyTango/pytango_pprint.py
@@ -0,0 +1,143 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = []
+
+__docformat__ = "restructuredtext"
+
+from _PyTango import *
+
+from device_server import AttributeAlarm, EventProperties
+from device_server import ChangeEventProp, PeriodicEventProp, ArchiveEventProp
+from device_server import AttributeConfig, AttributeConfig_2, AttributeConfig_3
+
+def __inc_param(obj, name):
+    ret  = not name.startswith('_')
+    ret &= not name in ('except_flags',)
+    ret &= not callable(getattr(obj,name))
+    return ret
+
+def __single_param(obj, param_name, f=repr, fmt='%s = %s'):
+    param_value = getattr(obj, param_name)
+    if param_name is 'data_type':
+        param_value = CmdArgType.values.get(param_value, param_value)
+    return fmt % (param_name, f(param_value))
+
+def __struct_params_s(obj, separator=', ', f=repr, fmt='%s = %s'):
+    """method wrapper for printing all elements of a struct"""
+    s = separator.join([__single_param(obj, n, f, fmt) for n in dir(obj) if __inc_param(obj,n)])
+    return s
+
+def __struct_params_repr(obj):
+    """method wrapper for representing all elements of a struct"""
+    return __struct_params_s(obj)
+
+def __struct_params_str(obj, fmt, f=repr):
+    """method wrapper for printing all elements of a struct."""
+    return __struct_params_s(obj, '\n', f=f, fmt=fmt)
+
+def __repr__Struct(self):
+    """repr method for struct"""
+    return '%s(%s)' % (self.__class__.__name__, __struct_params_repr(self))
+
+def __str__Struct_Helper(self, f=repr):
+    """str method for struct"""
+    attrs = [ n for n in dir(self) if __inc_param(self, n)]
+    fmt = attrs and '%%%ds = %%s' % max( map(len, attrs) ) or "%s = %s"
+    return '%s[\n%s]\n' % (self.__class__.__name__, __struct_params_str(self, fmt, f))
+
+def __str__Struct(self):
+    return __str__Struct_Helper(self, f=repr)
+
+def __str__Struct_extra(self):
+    return __str__Struct_Helper(self, f=str)
+
+def __registerSeqStr():
+    """helper function to make internal sequences printable"""
+    _SeqStr = lambda self: (self and "[%s]" % (", ".join(map(repr,self)))) or "[]"
+    _SeqRepr = lambda self: (self and "[%s]" % (", ".join(map(repr,self)))) or "[]"
+
+    seqs = (StdStringVector, StdLongVector, CommandInfoList,
+            AttributeInfoList, AttributeInfoListEx,
+            DeviceDataHistoryList,
+            GroupReplyList, GroupAttrReplyList, GroupCmdReplyList,
+            DbData, DbDevInfos, DbDevExportInfos, DbDevImportInfos, DbHistoryList)
+
+    for seq in seqs:
+        seq.__str__ = _SeqStr
+        seq.__repr__ = _SeqRepr
+
+import operator
+
+def __str__DevFailed(self):
+    if operator.isSequenceType(self.args):
+        return 'DevFailed[\n%s]' % '\n'.join(map(str,self.args))
+    return 'DevFailed[%s]' % (self.args)
+    
+def __repr__DevFailed(self):
+    return 'DevFailed(args = %s)' % repr(self.args)
+
+def __str__DevError(self):
+    desc = self.desc.replace("\n","\n           ")
+    s = """DevError[
+    desc = %s
+  origin = %s
+  reason = %s
+severity = %s]\n""" % (desc, self.origin, self.reason, self.severity)
+    return s
+
+def __registerStructStr():
+    """helper method to register str and repr methods for structures"""
+    structs = (LockerInfo, DevCommandInfo, AttributeDimension, CommandInfo,
+        DeviceInfo, DeviceAttributeConfig, AttributeInfo, AttributeAlarmInfo,
+        ChangeEventInfo, PeriodicEventInfo, ArchiveEventInfo,
+        AttributeEventInfo, AttributeInfoEx,
+        DeviceAttribute, DeviceAttributeHistory, DeviceData, DeviceDataHistory,
+        DbDatum, DbDevInfo, DbDevImportInfo, DbDevExportInfo, DbServerInfo,
+        GroupElement, GroupReply, GroupAttrReply, GroupCmdReply,
+        DevError, EventData, AttrConfEventData, DataReadyEventData,
+        AttributeConfig, AttributeConfig_2, AttributeConfig_3,
+        ChangeEventProp, PeriodicEventProp, ArchiveEventProp,
+        AttributeAlarm, EventProperties)
+
+    for struct in structs:
+        struct.__str__ = __str__Struct
+        struct.__repr__ = __repr__Struct
+
+    # special case for TimeVal: it already has a str representation itself
+    TimeVal.__repr__ = __repr__Struct
+
+    # special case for DevFailed: we want a better pretty print
+    # also, because it is an Exception it has the message attribute which
+    # generates a Deprecation warning in python 2.6
+    DevFailed.__str__ = __str__DevFailed
+    DevFailed.__repr__ = __repr__DevFailed
+
+    DevError.__str__ = __str__DevError
+
+def init(doc=True):
+    __registerSeqStr()
+    __registerStructStr()
diff --git a/PyTango/pyutil.py b/PyTango/pyutil.py
new file mode 100644
index 0000000..8a0cc83
--- /dev/null
+++ b/PyTango/pyutil.py
@@ -0,0 +1,670 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = [ "Util" ]
+
+__docformat__ = "restructuredtext"
+
+import os
+import copy
+import operator
+
+from _PyTango import _Util, Except, DevFailed, DbDevInfo
+from utils import document_method as __document_method
+#from utils import document_static_method as __document_static_method
+from globals import class_list
+from globals import cpp_class_list
+from globals import get_constructed_classes
+
+def __simplify_device_name(dev_name):
+    if dev_name.startswith("tango://"):
+        dev_name = dev_name[8:]
+    if dev_name.count("/") > 2:
+        dev_name = dev_name[dev_name.index("/")+1:]
+    return dev_name.lower()
+
+#
+# Methods on Util
+#
+
+def __Util__get_class_list(self):
+    """
+        get_class_list(self) -> seq<DeviceClass>
+
+                Returns a list of objects of inheriting from DeviceClass
+
+            Parameters : None
+
+            Return     : (seq<DeviceClass>) a list of objects of inheriting from DeviceClass"""
+    return get_constructed_classes()
+
+def __Util__create_device(self, klass_name, device_name, alias=None, cb=None):
+    """
+        create_device(self, klass_name, device_name, alias=None, cb=None) -> None
+        
+            Creates a new device of the given class in the database, creates a new
+            DeviceImpl for it and calls init_device (just like it is done for
+            existing devices when the DS starts up)
+    
+            An optional parameter callback is called AFTER the device is 
+            registered in the database and BEFORE the init_device for the
+            newly created device is called
+            
+            Throws PyTango.DevFailed:
+                - the device name exists already or
+                - the given class is not registered for this DS.
+                - the cb is not a callable
+            
+        New in PyTango 7.1.2
+        
+        Parameters :
+            - klass_name : (str) the device class name
+            - device_name : (str) the device name
+            - alias : (str) optional alias. Default value is None meaning do not create device alias
+            - cb : (callable) a callback that is called AFTER the device is registered
+                   in the database and BEFORE the init_device for the newly created
+                   device is called. Typically you may want to put device and/or attribute
+                   properties in the database here. The callback must receive a parameter:
+                   device name (str). Default value is None meaning no callback
+        
+        Return     : None"""
+    if cb is not None and not callable(cb):
+        Except.throw_exception("PyAPI_InvalidParameter",
+            "The optional cb parameter must be a python callable",
+            "Util.create_device")
+    
+    db = self.get_database()
+
+    device_name = __simplify_device_name(device_name)
+    
+    device_exists = True
+    try:
+        db.import_device(device_name)
+    except DevFailed, df:
+        device_exists = not df[0].reason == "DB_DeviceNotDefined"
+
+    # 1 - Make sure device name doesn't exist already in the database
+    if device_exists:
+        Except.throw_exception("PyAPI_DeviceAlreadyDefined", 
+            "The device %s is already defined in the database" % device_name,
+            "Util.create_device")
+
+    # 2 - Make sure the device class is known
+    klass_list = self.get_class_list()
+    klass = None
+    for k in klass_list:
+        name = k.get_name()
+        if name == klass_name:
+            klass = k
+            break
+    if klass is None:
+        Except.throw_exception("PyAPI_UnknownDeviceClass", 
+            "The device class %s could not be found" % klass_name,
+            "Util.create_device")
+            
+    # 3 - Create entry in the database (with alias if necessary)
+    dev_info = DbDevInfo()
+    dev_info.name = device_name
+    dev_info._class = klass_name
+    dev_info.server = self.get_ds_name()
+    
+    db.add_device(dev_info)
+    
+    if alias is not None:
+        db.put_device_alias(device_name, alias)
+
+    # from this point on, if anything wrong happens we need to clean the database
+    try:
+        # 4 - run the callback which tipically is used to initialize 
+        #     device and/or attribute properties in the database
+        if cb is not None:
+            cb(device_name)
+            
+        # 5 - Initialize device object on this server
+        k.device_factory([device_name])
+    except:
+        try:
+            if alias is not None:
+                db.delete_device_alias(alias)
+        except:
+            pass
+        db.delete_device(device_name)
+
+def __Util__delete_device(self, klass_name, device_name):
+    """
+        delete_device(self, klass_name, device_name) -> None
+        
+            Deletes an existing device from the database and from this running
+            server
+    
+            Throws PyTango.DevFailed:
+                - the device name doesn't exist in the database
+                - the device name doesn't exist in this DS.
+        
+        New in PyTango 7.1.2
+        
+        Parameters :
+            - klass_name : (str) the device class name
+            - device_name : (str) the device name
+        
+        Return     : None"""
+        
+    db = self.get_database()
+    device_name = __simplify_device_name(device_name)
+    device_exists = True
+    try:
+        db.import_device(device_name)
+    except DevFailed, df:
+        device_exists = not df[0].reason == "DB_DeviceNotDefined"
+
+    # 1 - Make sure device name exists in the database
+    if not device_exists:
+        Except.throw_exception("PyAPI_DeviceNotDefined", 
+            "The device %s is not defined in the database" % device_name,
+            "Util.delete_device")
+    
+    # 2 - Make sure device name is defined in this server
+    class_device_name = "%s::%s" % (klass_name, device_name)
+    ds = self.get_dserver_device()
+    dev_names = ds.query_device()
+    device_exists = False
+    for dev_name in dev_names:
+        p = dev_name.index("::")
+        dev_name = dev_name[:p] + dev_name[p:].lower()
+        if dev_name == class_device_name:
+            device_exists =True
+            break
+    if not device_exists:
+        Except.throw_exception("PyAPI_DeviceNotDefinedInServer", 
+            "The device %s is not defined in this server" % class_device_name,
+            "Util.delete_device")
+    
+    db.delete_device(device_name)
+    
+    dimpl = self.get_device_by_name(device_name)
+    
+    dc = dimpl.get_device_class()
+    dc.device_destroyer(device_name)
+
+    
+class Util(_Util):
+    """
+        This class is a used to store TANGO device server process data and to
+        provide the user with a set of utilities method.
+
+        This class is implemented using the singleton design pattern.
+        Therefore a device server process can have only one instance of this
+        class and its constructor is not public.
+
+            Example:
+                util = PyTango.Util.instance()
+                print util.get_host_name()
+        """
+
+    def __init__(self, args):
+        args = copy.copy(args)
+        args[0] = os.path.splitext(args[0])[0]
+        _Util.init(args)
+        _Util.init_python()
+
+    def add_TgClass(self, klass_device_class, klass_device, device_class_name=None):
+        """Register a new python tango class.
+           
+           Example:
+               util.add_TgClass(MotorClass, Motor)
+               util.add_TgClass(MotorClass, Motor, 'Motor') # equivalent to previous line"""
+               
+        if device_class_name is None:
+            device_class_name = klass_device.__name__
+        class_list.append((klass_device_class, klass_device, device_class_name))
+
+
+    def add_Cpp_TgClass(self, device_class_name, tango_device_class_name):
+        """Register a new C++ tango class.
+           
+           If there is a shared library file called MotorClass.so which
+           contains a MotorClass class and a _create_MotorClass_class method.
+           Example:
+               util.add_Cpp_TgClass('MotorClass', 'Motor')
+               
+           .. note: the parameter 'device_class_name' must match the shared
+           library name."""
+        cpp_class_list.append((device_class_name, tango_device_class_name))
+
+    def add_class(self, *args, **kwargs):
+        """
+            add_class(self, args, language="python") -> None
+            
+                Register a new tango class ('python' or 'c++').
+           
+                If language is 'python' then args must be the same as 
+                :meth:`PyTango.Util.add_TgClass`. Otherwise, args should be the ones
+                in :meth:`PyTango.Util.add_Cpp_TgClass`.
+            
+                Example:
+                    util.add_class(MotorClass, Motor)
+                    util.add_class('CounterClass', 'Counter', language='c++')
+           
+            New in PyTango 7.1.2"""
+        language = kwargs.get("language", "python")
+        f = self.add_TgClass
+        if language != "python":
+            f = f = self.add_Cpp_TgClass
+        return f(*args)
+
+def __init_Util():
+    _Util.get_class_list = __Util__get_class_list
+    _Util.create_device = __Util__create_device
+    _Util.delete_device = __Util__delete_device
+
+def __doc_Util():
+    def document_method(method_name, desc, append=True):
+        return __document_method(Util, method_name, desc, append)
+
+#    def document_static_method(method_name, desc, append=True):
+#        return __document_static_method(_Util, method_name, desc, append)
+
+#    document_static_method("instance", """
+#    instance(exit = True) -> Util
+#
+#            Static method that gets the singleton object reference.
+#            If the class has not been initialised with it's init method,
+#            this method print a message and abort the device server process
+#
+#        Parameters :
+#            - exit : (bool)
+#
+#        Return     : (Util) the tango Util object
+#    """ )
+
+    document_method("set_trace_level", """
+    set_trace_level(self, level) -> None
+
+            Set the process trace level.
+
+        Parameters :
+            - level : (int) the new process level
+        Return     : None
+    """ )
+
+    document_method("get_trace_level", """
+    get_trace_level(self) -> int
+
+            Get the process trace level.
+
+        Parameters : None
+        Return     : (int) the process trace level.
+    """ )
+
+    document_method("get_ds_inst_name", """
+    get_ds_inst_name(self) -> str
+
+            Get a COPY of the device server instance name.
+
+        Parameters : None
+        Return     : (str) a COPY of the device server instance name.
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("get_ds_exec_name", """
+    get_ds_exec_name(self) -> str
+
+            Get a COPY of the device server executable name.
+
+        Parameters : None
+        Return     : (str) a COPY of the device server executable name.
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("get_ds_name", """
+    get_ds_name(self) -> str
+
+            Get the device server name.
+            The device server name is the <device server executable name>/<the device server instance name>
+
+        Parameters : None
+        Return     : (str) device server name
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("get_host_name", """
+    get_host_name(self) -> str
+
+            Get the host name where the device server process is running.
+
+        Parameters : None
+        Return     : (str) the host name where the device server process is running
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("get_pid_str", """
+    get_pid_str(self) -> str
+
+            Get the device server process identifier as a string.
+
+        Parameters : None
+        Return     : (str) the device server process identifier as a string
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("get_pid", """
+    get_pid(self) -> TangoSys_Pid
+
+            Get the device server process identifier.
+
+        Parameters : None
+        Return     : (int) the device server process identifier
+    """ )
+
+    document_method("get_tango_lib_release", """
+    get_tango_lib_release(self) -> int
+
+            Get the TANGO library version number.
+
+        Parameters : None
+        Return     : (int) The Tango library release number coded in
+                     3 digits (for instance 550,551,552,600,....)
+    """ )
+
+    document_method("get_version_str", """
+    get_version_str(self) -> str
+
+            Get the IDL TANGO version.
+
+        Parameters : None
+        Return     : (str) the IDL TANGO version.
+
+        New in PyTango 3.0.4
+    """ )
+
+    document_method("get_server_version", """
+    get_server_version(self) -> str
+
+            Get the device server version.
+
+        Parameters : None
+        Return     : (str) the device server version.
+    """ )
+
+    document_method("set_server_version", """
+    set_server_version(self, vers) -> None
+
+            Set the device server version.
+
+        Parameters :
+            - vers : (str) the device server version
+        Return     : None
+    """ )
+
+    document_method("set_serial_model", """
+    set_serial_model(self, ser) -> None
+
+            Set the serialization model.
+
+        Parameters :
+            - ser : (SerialModel) the new serialization model. The serialization model must
+                    be one of BY_DEVICE, BY_CLASS, BY_PROCESS or NO_SYNC
+        Return     : None
+    """ )
+
+    document_method("get_serial_model", """
+    get_serial_model(self) ->SerialModel
+
+            Get the serialization model.
+
+        Parameters : None
+        Return     : (SerialModel) the serialization model
+    """ )
+
+    document_method("connect_db", """
+    connect_db(self) -> None
+
+            Connect the process to the TANGO database.
+            If the connection to the database failed, a message is
+            displayed on the screen and the process is aborted
+
+        Parameters : None
+        Return     : None
+    """ )
+
+    document_method("reset_filedatabase", """
+    reset_filedatabase(self) -> None
+
+            Reread the file database.
+
+        Parameters : None
+        Return     : None
+    """ )
+
+    document_method("unregister_server", """
+    unregister_server(self) -> None
+
+            Unregister a device server process from the TANGO database.
+
+        Parameters : None
+        Return     : None
+    """ )
+
+    document_method("get_dserver_device", """
+    get_dserver_device(self) -> DServer
+
+            Get a reference to the dserver device attached to the device server process.
+
+        Parameters : None
+        Return     : (DServer) the dserver device attached to the device server process
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("server_init", """
+    server_init(self, with_window = False) -> None
+
+            Initialize all the device server pattern(s) embedded in a device server process.
+
+        Parameters :
+            - with_window : (bool) default value is False
+        Return     : None
+
+        Throws     : DevFailed If the device pattern initialistaion failed
+    """ )
+
+    document_method("server_run", """
+    server_run(self) -> None
+
+            Run the CORBA event loop.
+            This method runs the CORBA event loop. For UNIX or Linux operating system,
+            this method does not return. For Windows in a non-console mode, this method
+            start a thread which enter the CORBA event loop.
+
+        Parameters : None
+        Return     : None
+    """ )
+
+    document_method("trigger_cmd_polling", """
+    trigger_cmd_polling(self, dev, name) -> None
+
+            Trigger polling for polled command.
+            This method send the order to the polling thread to poll one object registered
+            with an update period defined as "externally triggerred"
+
+        Parameters :
+            - dev : (DeviceImpl) the TANGO device
+            - name : (str) the command name which must be polled
+        Return     : None
+
+        Throws     : DevFailed If the call failed
+    """ )
+
+    document_method("trigger_attr_polling", """
+    trigger_attr_polling(self, dev, name) -> None
+
+            Trigger polling for polled attribute.
+            This method send the order to the polling thread to poll one object registered
+            with an update period defined as "externally triggerred"
+
+        Parameters :
+            - dev : (DeviceImpl) the TANGO device
+            - name : (str) the attribute name which must be polled
+        Return     : None
+    """ )
+
+    document_method("set_polling_threads_pool_size", """
+    set_polling_threads_pool_size(self, thread_nb) -> None
+
+            Set the polling threads pool size.
+
+        Parameters :
+            - thread_nb : (int) the maximun number of threads in the polling threads pool
+        Return     : None
+
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("get_polling_threads_pool_size", """
+    get_polling_threads_pool_size(self) -> int
+
+            Get the polling threads pool size.
+
+        Parameters : None
+        Return     : (int) the maximun number of threads in the polling threads pool
+    """ )
+    
+    document_method("get_sub_dev_diag", """
+    get_sub_dev_diag(self) -> SubDevDiag
+
+            Get the internal sub device manager
+
+        Parameters : None
+        Return     : (SubDevDiag) the sub device manager
+        
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("reset_filedatabase", """
+    reset_filedatabase(self) -> None
+
+            Reread the file database
+
+        Parameters : None
+        Return     : None
+        
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("get_database", """
+    get_database(self) -> Database
+
+            Get a reference to the TANGO database object
+
+        Parameters : None
+        Return     : (Database) the database
+        
+        New in PyTango 7.0.0
+    """ )
+
+    document_method("unregister_server", """
+    unregister_server(self) -> None
+
+            Unregister a device server process from the TANGO database.
+            If the database call fails, a message is displayed on the screen 
+            and the process is aborted
+
+        Parameters : None
+        Return     : None
+        
+        New in PyTango 7.0.0
+    """ )
+    
+    document_method("get_device_list_by_class", """
+    get_device_list_by_class(self, class_name) -> sequence<DeviceImpl>
+
+            Get the list of device references for a given TANGO class.
+            Return the list of references for all devices served by one implementation
+            of the TANGO device pattern implemented in the process.
+            
+        Parameters :
+            - class_name : (str) The TANGO device class name
+            
+        Return     : (sequence<DeviceImpl>) The device reference list
+        
+        New in PyTango 7.0.0
+    """ )
+    
+    document_method("get_device_by_name", """
+    get_device_by_name(self, dev_name) -> DeviceImpl
+
+            Get a device reference from its name
+
+        Parameters :
+            - dev_name : (str) The TANGO device name
+        Return     : (DeviceImpl) The device reference
+        
+        New in PyTango 7.0.0
+    """ )
+    
+    document_method("get_dserver_device", """
+    get_dserver_device(self) -> DServer
+
+            Get a reference to the dserver device attached to the device server process
+
+        Parameters : None
+        Return     : (DServer) A reference to the dserver device
+        
+        New in PyTango 7.0.0
+    """ )
+    
+    document_method("get_device_list", """
+    get_device_list(self) -> sequence<DeviceImpl>
+
+            Get device list from name.
+            It is possible to use a wild card ('*') in the name parameter
+            (e.g. "*", "/tango/tangotest/n*", ...)
+            
+        Parameters : None
+        Return     : (sequence<DeviceImpl>) the list of device objects
+        
+        New in PyTango 7.0.0
+    """ )
+    
+#    document_static_method("init_python", """
+#    init_python() -> None
+#
+#            Static method
+#            For internal usage.
+#
+#        Parameters : None
+#        Return     : None
+#    """ )
+
+def init(doc=True):
+    __init_Util()
+    if doc:
+        __doc_Util()
diff --git a/PyTango/release.py b/PyTango/release.py
new file mode 100644
index 0000000..29cf4bc
--- /dev/null
+++ b/PyTango/release.py
@@ -0,0 +1,61 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = [ "Release" ]
+
+__docformat__ = "restructuredtext"
+
+class Release:
+    """
+        Release information:
+            - name : (str) package name
+            - version_info : (tuple<int,int,int,str,int>) The five components of the version number: major, minor, micro, releaselevel, and serial.
+            - version : (str) package version in format <major>.<minor>.<micro>
+            - version_long : (str) package version in format <major>.<minor>.<micro><releaselevel><serial>
+            - version_description : (str) short description for the current version
+            - version_number : (int) <major>*100 + <minor>*10 + <micro>
+            - description : (str) package description
+            - long_description : (str) longer package description
+            - authors : (dict<str(last name), tuple<str(full name),str(email)>>) package authors
+            - url : (str) package url
+            - download_url : (str) package download url
+            - platform : (seq<str>) list of available platforms
+            - keywords : (seq<str>) list of keywords
+            - licence : (str) the licence"""
+    name = 'PyTango'
+    version_info = (7, 2, 0, 'dev', 0)
+    version = '.'.join(map(str, version_info[:3]))
+    version_long = version + ''.join(map(str, version_info[3:]))
+    version_description = 'This version implements the C++ Tango 7.2 API.'
+    version_number = int(version.replace('.',''))
+    description = 'A python binding for the Tango control system'
+    long_description = 'This module implements the Python Tango Device API mapping'
+    license = 'LGPL'
+    authors = { 'Coutinho' : ('Tiago Coutinho' , 'tcoutinho at cells.es') }
+    url = 'http://packages.python.org/PyTango'
+    download_url = 'http://pypi.python.org/packages/source/P/PyTango'
+    platform = ['Linux', 'Windows XP/2000/NT', 'Windows 95/98/ME']
+    keywords = ['Tango', 'CORBA', 'binding']
diff --git a/PyTango/tango_numpy.py b/PyTango/tango_numpy.py
new file mode 100644
index 0000000..8b8996d
--- /dev/null
+++ b/PyTango/tango_numpy.py
@@ -0,0 +1,151 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = [ "NumpyType", "numpy_type", "numpy_spectrum", "numpy_image" ]
+
+__docformat__ = "restructuredtext"
+
+import _PyTango
+
+def _numpy_invalid(*args, **kwds):
+    _PyTango.Except.throw_exception(
+        "PyTango_InvalidConversion",
+        "There's no registered conversor to numpy.",
+        "NumpyType.tango_to_numpy"
+    )
+
+try:
+    import numpy
+    import operator
+
+    from attribute_proxy import AttributeProxy
+
+    ArgType = _PyTango.CmdArgType
+    AttributeInfo = _PyTango.AttributeInfo
+    Attribute = _PyTango.Attribute
+
+    class NumpyType(object):
+
+        DevShort = numpy.int16
+        DevLong = numpy.int32
+        DevDouble = numpy.float64
+        DevFloat = numpy.float32
+        DevBoolean = numpy.bool8
+        DevUShort = numpy.uint16
+        DevULong = numpy.uint32
+        DevUChar = numpy.ubyte
+        DevLong64 = numpy.int64
+        DevULong64 = numpy.uint64
+
+        mapping = {
+            ArgType.DevShort: DevShort,
+            ArgType.DevLong: DevLong,
+            ArgType.DevDouble: DevDouble,
+            ArgType.DevFloat: DevFloat,
+            ArgType.DevBoolean: DevBoolean,
+            ArgType.DevUShort: DevUShort,
+            ArgType.DevULong: DevULong,
+            ArgType.DevUChar: DevUChar,
+            ArgType.DevLong64: DevLong64,
+            ArgType.DevULong: DevULong64,
+        }
+
+        @staticmethod
+        def tango_to_numpy(param):
+            if isinstance(param, ArgType):
+                tg_type = param
+            if isinstance(param, AttributeInfo): # or AttributeInfoEx
+                tg_type = param.data_type
+            elif isinstance(param, Attribute):
+                tg_type = param.get_data_type()
+            elif isinstance(param, AttributeProxy):
+                tg_type = param.get_config().data_type
+            else:
+                tg_type = param
+            try:
+                return NumpyType.mapping[tg_type]
+            except Exception:
+                _numpy_invalid()
+
+        @staticmethod
+        def spectrum(tg_type, dim_x):
+            """
+            numpy_spectrum(self, tg_type, dim_x, dim_y) -> numpy.array
+            numpy_spectrum(self, tg_type, sequence) -> numpy.array
+
+                    Get a square numpy array to be used with PyTango.
+                    One version gets dim_x and creates an object with
+                    this size. The other version expects any sequence to
+                    convert.
+
+                Parameters:
+                    - tg_type : (ArgType): The tango type. For convenience, it
+                                can also extract this information from an
+                                Attribute, AttributeInfo or AttributeProxy
+                                object.
+                    - dim_x : (int)
+                    - sequence:
+            """
+            np_type = NumpyType.tango_to_numpy(tg_type)
+            if operator.isSequenceType(dim_x):
+                return numpy.array(dim_x, dtype=np_type)
+            else:
+                return numpy.ndarray(shape=(dim_x,), dtype=np_type)
+
+        @staticmethod
+        def image(tg_type, dim_x, dim_y=None):
+            """
+            numpy_image(self, tg_type, dim_x, dim_y) -> numpy.array
+            numpy_image(self, tg_type, sequence) -> numpy.array
+
+                    Get a square numpy array to be used with PyTango.
+                    One version gets dim_x and dim_y and creates an object with
+                    this size. The other version expects a square sequence of
+                    sequences to convert.
+
+                Parameters:
+                    - tg_type : (ArgType): The tango type. For convenience, it
+                                can also extract this information from an
+                                Attribute, AttributeInfo or AttributeProxy
+                                object.
+                    - dim_x : (int)
+                    - dim_y : (int)
+                    - sequence:
+            """
+            np_type = NumpyType.tango_to_numpy(tg_type)
+            if dim_y is None:
+                return numpy.array(dim_x, dtype=np_type)
+            else:
+                return numpy.ndarray(shape=(dim_y,dim_x,), dtype=np_type)
+
+    numpy_spectrum = NumpyType.spectrum
+    numpy_image = NumpyType.image
+    numpy_type = NumpyType.tango_to_numpy
+except Exception:
+    NumpyType = None
+    numpy_spectrum = _numpy_invalid
+    numpy_image = _numpy_invalid
+    numpy_type = _numpy_invalid
diff --git a/PyTango/time_val.py b/PyTango/time_val.py
new file mode 100644
index 0000000..60e12ce
--- /dev/null
+++ b/PyTango/time_val.py
@@ -0,0 +1,196 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = []
+
+__docformat__ = "restructuredtext"
+
+import time
+import datetime
+import operator
+
+from _PyTango import TimeVal
+
+def __TimeVal__init(self, a=None, b=None, c=None):
+    TimeVal.__init_original(self)
+    if a is None: 
+        return
+
+    if isinstance(a, datetime.datetime):
+        assert(b is None and c is None)
+        a = time.mktime(a.timetuple()) + a.microsecond*1E-6
+
+    elif operator.isNumberType(a):
+        if b is None:
+            self.tv_sec = int(a)
+            usec = (a - self.tv_sec) * 1E6
+            self.tv_usec = int(usec)
+            self.tv_nsec = int((usec - self.tv_usec) * 1E3)
+        else:
+            self.tv_sec, self.tv_usec, self.tv_nsec = a, b, c
+
+def __TimeVal__totime(self):
+    """
+    totime(self) -> float
+    
+        Returns a float representing this time value
+    
+        Parameters : None
+        Return     : a float representing the time value
+        
+    .. versionadded:: 7.1.0"""
+    return self.tv_sec + 1E-6*self.tv_usec + 1E-9*self.tv_nsec
+
+def __TimeVal__todatetime(self):
+    """
+    todatetime(self) -> datetime.datetime
+    
+        Returns a :class:`datetime.datetime` object representing
+        the same time value
+    
+        Parameters : None
+        Return     : (datetime.datetime) the time value in datetime format
+        
+    .. versionadded:: 7.1.0"""
+    return datetime.datetime.fromtimestamp(self.totime())
+
+def __TimeVal__fromtimestamp(ts):
+    """
+    fromtimestamp(ts) -> TimeVal
+
+        A static method returning a :class:`PyTango.TimeVal` object representing
+        the given timestamp
+    
+        Parameters :
+            - ts : (float) a timestamp
+        Return     : (TimeVal) representing the given timestamp
+        
+    .. versionadded:: 7.1.0"""
+    return TimeVal(ts)
+
+def __TimeVal__fromdatetime(dt):
+    """
+    fromdatetime(dt) -> TimeVal
+
+        A static method returning a :class:`PyTango.TimeVal` object representing
+        the given :class:`datetime.datetime`
+    
+        Parameters :
+            - dt : (datetime.datetime) a datetime object
+        Return     : (TimeVal) representing the given timestamp
+        
+    .. versionadded:: 7.1.0
+
+    .. versionadded:: 7.1.2
+        Documented
+    """
+    return TimeVal(dt)
+
+def __TimeVal__now():
+    """
+    now() -> TimeVal
+
+        A static method returning a :class:`PyTango.TimeVal` object representing
+        the current time
+    
+        Parameters : None
+        Return     : (TimeVal) representing the current time
+        
+    .. versionadded:: 7.1.0
+
+    .. versionadded:: 7.1.2
+        Documented
+    """
+    return TimeVal(time.time())
+
+def __TimeVal__strftime(self, format):
+    """
+    strftime(self, format) -> str
+
+        Convert a time value to a string according to a format specification.
+    
+        Parameters : 
+            format : (str) See the python library reference manual for formatting codes
+        Return     : (str) a string representing the time according to a format specification.
+        
+    .. versionadded:: 7.1.0
+
+    .. versionadded:: 7.1.2
+        Documented
+    """
+    return self.todatetime().strftime(format)
+
+def __TimeVal__isoformat(self, sep='T'):
+    """
+    isoformat(self, sep='T') -> str
+
+        Returns a string in ISO 8601 format, YYYY-MM-DDTHH:MM:SS[.mmmmmm][+HH:MM]
+    
+        Parameters : 
+            sep : (str) sep is used to separate the year from the time, and defaults to 'T'
+        Return     : (str) a string representing the time according to a format specification.
+        
+    .. versionadded:: 7.1.0
+
+    .. versionadded:: 7.1.2
+        Documented
+    
+    .. versionchanged:: 7.1.2
+        The `sep` parameter is not mandatory anymore and defaults to 'T' (same as :meth:`datetime.datetime.isoformat`)
+    """
+    return self.todatetime().isoformat(sep)
+
+def __TimeVal__str__(self):
+    """
+    __str__(self) -> str
+
+        Returns a string representation of TimeVal
+    
+        Parameters : None
+        Return     : (str) a string representing the time (same as :class:`datetime.datetime`)
+        
+    .. versionadded:: 7.1.0
+
+    .. versionadded:: 7.1.2
+        Documented
+    """
+    return str(self.todatetime())
+
+def __init_TimeVal():
+    TimeVal.__init_original = TimeVal.__init__
+    TimeVal.__init__ = __TimeVal__init
+    TimeVal.totime = __TimeVal__totime
+    TimeVal.todatetime = __TimeVal__todatetime
+    TimeVal.fromtimestamp = staticmethod(__TimeVal__fromtimestamp)
+    TimeVal.fromdatetime = staticmethod(__TimeVal__fromdatetime)
+    TimeVal.now = staticmethod(__TimeVal__now)
+    TimeVal.strftime = __TimeVal__strftime
+    TimeVal.isoformat = __TimeVal__isoformat
+    TimeVal.__str__ = __TimeVal__str__
+    
+def init(doc=True):
+    __init_TimeVal()
+
diff --git a/PyTango/utils.py b/PyTango/utils.py
new file mode 100644
index 0000000..fb658ce
--- /dev/null
+++ b/PyTango/utils.py
@@ -0,0 +1,648 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+from __future__ import with_statement
+
+__all__ = [ "is_scalar_type", "is_array_type", "is_numerical_type", 
+            "is_int_type", "is_float_type", "obj_2_str", "seqStr_2_obj",
+            "document_method", "document_static_method", "document_enum",
+            "CaselessList", "CaselessDict" ]
+
+__docformat__ = "restructuredtext"
+
+import sys
+import os
+import socket
+import types
+import operator
+
+from _PyTango import StdStringVector, DbData, DbDevInfos, DbDevExportInfos, CmdArgType, AttrDataFormat
+
+_scalar_int_types = (CmdArgType.DevShort, CmdArgType.DevUShort,
+    CmdArgType.DevInt, CmdArgType.DevLong, CmdArgType.DevULong,
+    CmdArgType.DevLong64, CmdArgType.DevULong64)
+
+_scalar_float_types = (CmdArgType.DevFloat, CmdArgType.DevDouble,)
+
+_scalar_numerical_types = _scalar_int_types + _scalar_float_types
+
+_scalar_str_types = (CmdArgType.DevString, CmdArgType.ConstDevString,)
+
+_scalar_types = _scalar_numerical_types + _scalar_str_types + \
+    (CmdArgType.DevBoolean, CmdArgType.DevEncoded,
+     CmdArgType.DevUChar, CmdArgType.DevVoid)
+
+_array_int_types = (CmdArgType.DevVarShortArray, CmdArgType.DevVarUShortArray,
+                    CmdArgType.DevVarLongArray, CmdArgType.DevVarULongArray,
+                    CmdArgType.DevVarLong64Array, CmdArgType.DevVarULong64Array)
+
+_array_float_types = (CmdArgType.DevVarFloatArray, CmdArgType.DevVarDoubleArray)
+
+_array_numerical_types = _array_int_types + _array_float_types
+
+_array_types = _array_numerical_types + (CmdArgType.DevVarBooleanArray,
+    CmdArgType.DevVarStringArray,
+    CmdArgType.DevVarCharArray, CmdArgType.DevVarDoubleStringArray,
+    CmdArgType.DevVarLongStringArray)
+
+_scalar_to_array_type = {
+    CmdArgType.DevBoolean : CmdArgType.DevVarBooleanArray,
+    CmdArgType.DevUChar : CmdArgType.DevVarCharArray,
+    CmdArgType.DevShort : CmdArgType.DevVarShortArray,
+    CmdArgType.DevUShort : CmdArgType.DevVarUShortArray,
+    CmdArgType.DevInt : CmdArgType.DevVarLongArray,
+    CmdArgType.DevLong : CmdArgType.DevVarLongArray,
+    CmdArgType.DevULong : CmdArgType.DevVarULongArray,
+    CmdArgType.DevLong64 : CmdArgType.DevVarLong64Array,
+    CmdArgType.DevULong64 : CmdArgType.DevVarULong64Array,
+    CmdArgType.DevFloat : CmdArgType.DevVarFloatArray,
+    CmdArgType.DevDouble : CmdArgType.DevVarDoubleArray,
+    CmdArgType.DevString : CmdArgType.DevVarStringArray,
+    CmdArgType.ConstDevString : CmdArgType.DevVarStringArray,
+}
+
+def is_scalar(tg_type):
+    global _scalar_types
+    return tg_type in _scalar_types
+
+is_scalar_type = is_scalar
+
+def is_array(tg_type):
+    global _array_types
+    return tg_type in _array_types
+
+is_array_type = is_array
+
+def is_numerical(tg_type, inc_array=False):
+    global _scalar_numerical_types, _array_numerical_types
+    if tg_type in _scalar_numerical_types:
+        return True
+    if not inc_array:
+        return False
+    return tg_type in _array_numerical_types
+
+is_numerical_type = is_numerical
+
+def is_int(tg_type, inc_array=False):
+    global _scalar_int_types, _array_int_types
+    if tg_type in _scalar_int_types:
+        return True
+    if not inc_array:
+        return False
+    return tg_type in _array_int_types
+
+is_int_type = is_int
+
+def is_float(tg_type, inc_array=False):
+    global _scalar_float_types, _array_float_types
+    if tg_type in _scalar_float_types:
+        return True
+    if not inc_array:
+        return False
+    return tg_type in _array_float_types
+
+is_float_type = is_float
+
+def seq_2_StdStringVector(seq, vec=None):
+    if vec is None:
+        if isinstance(seq, StdStringVector): return seq
+        vec = StdStringVector()
+    if not isinstance(vec, StdStringVector):
+        raise TypeError('vec must be a PyTango.StdStringVector')
+    for e in seq: vec.append(str(e))
+    return vec
+
+def StdStringVector_2_seq(vec, seq=None):
+    if seq is None: seq = []
+    if not isinstance(vec, StdStringVector):
+        raise TypeError('vec must be a PyTango.StdStringVector')
+    for e in vec: seq.append(str(e))
+    return seq
+
+def seq_2_StdDoubleVector(seq, vec=None):
+    if vec is None:
+        if isinstance(seq, StdDoubleVector): return seq
+        vec = StdDoubleVector()
+    if not isinstance(vec, StdDoubleVector):
+        raise TypeError('vec must be a PyTango.StdDoubleVector')
+    for e in seq: vec.append(str(e))
+    return vec
+
+def StdDoubleVector_2_seq(vec, seq=None):
+    if seq is None: seq = []
+    if not isinstance(vec, StdDoubleVector):
+        raise TypeError('vec must be a PyTango.StdDoubleVector')
+    for e in vec: sec.append(float(e))
+    return seq
+
+def seq_2_DbDevInfos(seq, vec=None):
+    if vec is None:
+        if isinstance(seq, DbDevInfos): return seq
+        vec = DbDevInfos()
+    if not isinstance(vec, DbDevInfos):
+        raise TypeError('vec must be a PyTango.DbDevInfos')
+    for e in seq: vec.append(e)
+    return vec
+
+def seq_2_DbDevExportInfos(seq, vec=None):
+    if vec is None:
+        if isinstance(seq, DbDevExportInfos): return seq
+        vec = DbDevExportInfos()
+    if not isinstance(vec, DbDevExportInfos):
+        raise TypeError('vec must be a PyTango.DbDevExportInfos')
+    for e in seq: vec.append(e)
+    return vec
+
+def seq_2_DbData(seq, vec=None):
+    if vec is None:
+        if isinstance(seq, DbData): return seq
+        vec = DbData()
+    if not isinstance(vec, DbData):
+        raise TypeError('vec must be a PyTango.DbData')
+    for e in seq: vec.append(e)
+    return vec
+
+def DbData_2_dict(db_data, d=None):
+    if d is None: d = {}
+    if not isinstance(db_data, DbData):
+        raise TypeError('db_data must be a PyTango.DbData. A %s found instead' % type(db_data))
+    for db_datum in db_data:
+        d[db_datum.name] = db_datum.value_string
+    return d
+
+def seqStr_2_obj(seq, tg_type, tg_format=None):
+    if tg_format:
+        return _seqStr_2_obj_from_type_format(seq, tg_type, tg_format)
+    return _seqStr_2_obj_from_type(seq, tg_type)
+
+def _seqStr_2_obj_from_type(seq, tg_type):
+    
+    if type(seq) in types.StringTypes:
+        seq = (seq,)
+    
+    #    Scalar cases
+    global _scalar_int_types
+    if tg_type in _scalar_int_types:
+        return int(seq[0])
+
+    global _scalar_float_types
+    if tg_type in _scalar_float_types:
+        return float(seq[0])
+
+    global _scalar_str_types
+    if tg_type in _scalar_str_types:
+        return seq[0]
+
+    if tg_type == CmdArgType.DevBoolean:
+        return seq[0].lower() == 'true'
+    
+    #sequence cases
+    if tg_type in (CmdArgType.DevVarCharArray, CmdArgType.DevVarStringArray):
+        return seq
+
+    global _array_int_types
+    if tg_type in _array_int_types:
+        argout = []
+        for x in seq:
+            argout.append(int(x))
+        return argout
+
+    global _array_float_types
+    if tg_type in _array_float_types:
+        argout = []
+        for x in seq:
+            argout.append(float(x))
+        return argout
+
+    if tg_type == CmdArgType.DevVarBooleanArray:
+        argout = []
+        for x in seq:
+            argout.append(x.lower() == 'true')
+        return argout        
+
+    return []
+
+def _seqStr_2_obj_from_type_format(seq, tg_type, tg_format):
+    if tg_format == AttrDataFormat.SCALAR:
+        return _seqStr_2_obj_from_type(tg_type, seq)
+    elif tg_format == AttrDataFormat.SPECTRUM:
+        return _seqStr_2_obj_from_type(_scalar_to_array_type(tg_type), seq)
+    elif tg_format == AttrDataFormat.IMAGE:
+        if tg_type == CmdArgType.DevString:
+            return seq
+
+        global _scalar_int_types
+        if tg_type in _scalar_int_types:
+            argout = []
+            for x in seq:
+                tmp = []
+                for y in x:
+                    tmp.append(int(y))
+                argout.append(tmp)
+            return argout
+
+        global _scalar_float_types
+        if tg_type in _scalar_float_types:
+            argout = []
+            for x in seq:
+                tmp = []
+                for y in x:
+                    tmp.append(float(y))
+                argout.append(tmp)
+            return argout
+    
+    #UNKNOWN_FORMAT
+    return _seqStr_2_obj_from_type(tg_type, seq)
+
+def obj_2_str(obj, tg_type):
+    """
+        obj_2_str(obj, tg_type) -> str
+
+                Converts a python object into a string according to the given tango type
+
+            Parameters :
+                - obj : (object) the object to be converted
+                - tg_type : (CmdArgType) tango type
+            Return     : (str) a string representation of the given object"""
+    ret = ""
+    if tg_type in _scalar_types:
+        # scalar cases
+        if operator.isSequenceType(obj):
+            if not len(obj):
+                return ret
+            obj = obj[0]
+        ret = str(obj).rstrip()
+    else:
+        # sequence cases
+        ret = '\n'.join([ str(i) for i in obj ])
+    return ret
+
+def copy_doc(klass, fnname):
+    """Copies documentation string of a method from the super class into the rewritten method of the given class"""
+    getattr(klass, fnname).im_func.__doc__ = getattr(klass.__base__, fnname).im_func.__doc__
+
+def document_method(klass, method_name, d, add=True):
+    if add:
+        cpp_doc = getattr(klass, method_name).__doc__
+        if cpp_doc:
+            getattr(klass, method_name).im_func.__doc__ = "%s\n%s" % (d, cpp_doc)
+            return
+    getattr(klass, method_name).im_func.__doc__ = d
+
+def document_static_method(klass, method_name, d, add=True):
+    if add:
+        cpp_doc = getattr(klass, method_name).__doc__
+        if cpp_doc:
+            getattr(klass, method_name).__doc__ = "%s\n%s" % (d, cpp_doc)
+            return
+    getattr(klass, method_name).__doc__ = d
+
+def document_enum(klass, enum_name, desc, append=True):
+    # derived = type(base)('derived', (base,), {'__doc__': 'desc'})
+
+    # Get the original enum type
+    base = getattr(klass, enum_name)
+
+    # Prepare the new docstring
+    if append and base.__doc__ is not None:
+        desc = base.__doc__ + "\n" + desc
+
+    # Create a new type, derived from the original. Only difference
+    # is the docstring.
+    derived = type(base)(enum_name, (base,), {'__doc__': desc})
+
+    # Replace the original enum type with the new one
+    setattr(klass, enum_name, derived)
+
+class CaselessList(list):
+    """A case insensitive lists that has some caseless methods. Only allows 
+    strings as list members. Most methods that would normally return a list, 
+    return a CaselessList. (Except list() and lowercopy())
+    Sequence Methods implemented are :
+    __contains__, remove, count, index, append, extend, insert,
+    __getitem__, __setitem__, __getslice__, __setslice__
+    __add__, __radd__, __iadd__, __mul__, __rmul__
+    Plus Extra methods:
+    findentry, copy , lowercopy, list
+    Inherited methods :
+    __imul__, __len__, __iter__, pop, reverse, sort
+    """
+    def __init__(self, inlist=[]):
+        list.__init__(self)
+        for entry in inlist:
+            if not isinstance(entry, str): 
+                raise TypeError('Members of this object must be strings. ' \
+                                'You supplied \"%s\" which is \"%s\"' % 
+                                (entry, type(entry)))
+            self.append(entry)
+
+    def findentry(self, item):
+        """A caseless way of checking if an item is in the list or not.
+        It returns None or the entry."""
+        if not isinstance(item, str): 
+            raise TypeError('Members of this object must be strings. '\
+                            'You supplied \"%s\"' % type(item))
+        for entry in self:
+            if item.lower() == entry.lower(): return entry
+        return None
+    
+    def __contains__(self, item):
+        """A caseless way of checking if a list has a member in it or not."""
+        for entry in self:
+            if item.lower() == entry.lower(): return True
+        return False
+        
+    def remove(self, item):
+        """Remove the first occurence of an item, the caseless way."""
+        for entry in self:
+            if item.lower() == entry.lower():
+                list.remove(self, entry)
+                return
+        raise ValueError(': list.remove(x): x not in list')
+    
+    def copy(self):
+        """Return a CaselessList copy of self."""
+        return CaselessList(self)
+
+    def list(self):
+        """Return a normal list version of self."""
+        return list(self)
+        
+    def lowercopy(self):
+        """Return a lowercase (list) copy of self."""
+        return [entry.lower() for entry in self]
+    
+    def append(self, item):
+        """Adds an item to the list and checks it's a string."""
+        if not isinstance(item, str): 
+            raise TypeError('Members of this object must be strings. ' \
+                            'You supplied \"%s\"' % type(item))
+        list.append(self, item)
+        
+    def extend(self, item):
+        """Extend the list with another list. Each member of the list must be 
+        a string."""
+        if not isinstance(item, list): 
+            raise TypeError('You can only extend lists with lists. ' \
+                            'You supplied \"%s\"' % type(item))
+        for entry in item:
+            if not isinstance(entry, str): 
+                raise TypeError('Members of this object must be strings. '\
+                                'You supplied \"%s\"' % type(entry))
+            list.append(self, entry)        
+
+    def count(self, item):
+        """Counts references to 'item' in a caseless manner.
+        If item is not a string it will always return 0."""
+        if not isinstance(item, str): return 0
+        count = 0
+        for entry in self:
+            if item.lower() == entry.lower():
+                count += 1
+        return count    
+
+    def index(self, item, minindex=0, maxindex=None):
+        """Provide an index of first occurence of item in the list. (or raise 
+        a ValueError if item not present)
+        If item is not a string, will raise a TypeError.
+        minindex and maxindex are also optional arguments
+        s.index(x[, i[, j]]) return smallest k such that s[k] == x and i <= k < j
+        """
+        if maxindex == None: maxindex = len(self)
+        minindex = max(0, minindex)-1
+        maxindex = min(len(self), maxindex)
+        if not isinstance(item, str): 
+            raise TypeError('Members of this object must be strings. '\
+                            'You supplied \"%s\"' % type(item))
+        index = minindex
+        while index < maxindex:
+            index += 1
+            if item.lower() == self[index].lower():
+                return index
+        raise ValueError(': list.index(x): x not in list')
+    
+    def insert(self, i, x):
+        """s.insert(i, x) same as s[i:i] = [x]
+        Raises TypeError if x isn't a string."""
+        if not isinstance(x, str): 
+            raise TypeError('Members of this object must be strings. ' \
+                            'You supplied \"%s\"' % type(x))
+        list.insert(self, i, x)
+
+    def __setitem__(self, index, value):
+        """For setting values in the list.
+        index must be an integer or (extended) slice object. (__setslice__ used 
+        for simple slices)
+        If index is an integer then value must be a string.
+        If index is a slice object then value must be a list of strings - with 
+        the same length as the slice object requires.
+        """
+        if isinstance(index, int):
+            if not isinstance(value, str): 
+                raise TypeError('Members of this object must be strings. ' \
+                                'You supplied \"%s\"' % type(value))
+            list.__setitem__(self, index, value)
+        elif isinstance(index, slice):
+            if not hasattr(value, '__len__'): 
+                raise TypeError('Value given to set slice is not a sequence object.')
+            for entry in value:
+                if not isinstance(entry, str): 
+                    raise TypeError('Members of this object must be strings. ' \
+                                    'You supplied \"%s\"' % type(entry))
+            list.__setitem__(self, index, value)
+        else:
+            raise TypeError('Indexes must be integers or slice objects.')
+
+    def __setslice__(self, i, j, sequence):
+        """Called to implement assignment to self[i:j]."""
+        for entry in sequence:
+            if not isinstance(entry, str): 
+                raise TypeError('Members of this object must be strings. ' \
+                                'You supplied \"%s\"' % type(entry))
+        list.__setslice__(self, i, j, sequence)
+
+    def __getslice__(self, i, j):
+        """Called to implement evaluation of self[i:j].
+        Although the manual says this method is deprecated - if I don't define 
+        it the list one is called.
+        (Which returns a list - this returns a CaselessList)"""
+        return CaselessList(list.__getslice__(self, i, j))
+
+    def __getitem__(self, index):
+        """For fetching indexes.
+        If a slice is fetched then the list returned is a CaselessList."""
+        if not isinstance(index, slice):
+            return list.__getitem__(self, index)
+        else:
+            return CaselessList(list.__getitem__(self, index))
+            
+    def __add__(self, item):
+        """To add a list, and return a CaselessList.
+        Every element of item must be a string."""
+        return CaselessList(list.__add__(self, item))
+
+    def __radd__(self, item):
+        """To add a list, and return a CaselessList.
+        Every element of item must be a string."""
+        return CaselessList(list.__add__(self, item))
+    
+    def __iadd__(self, item):
+        """To add a list in place."""
+        for entry in item: self.append(entry)
+
+    def __mul__(self, item):
+        """To multiply itself, and return a CaselessList.
+        Every element of item must be a string."""
+        return CaselessList(list.__mul__(self, item))
+
+    def __rmul__(self, item):
+        """To multiply itself, and return a CaselessList.
+        Every element of item must be a string."""
+        return CaselessList(list.__rmul__(self, item))
+
+
+class CaselessDict(dict):
+    def __init__(self, other=None):
+        if other:
+            # Doesn't do keyword args
+            if isinstance(other, dict):
+                for k,v in other.items():
+                    dict.__setitem__(self, k.lower(), v)
+            else:
+                for k,v in other:
+                    dict.__setitem__(self, k.lower(), v)
+    
+    def __getitem__(self, key):
+        return dict.__getitem__(self, key.lower())
+    
+    def __setitem__(self, key, value):
+        dict.__setitem__(self, key.lower(), value)
+    
+    def __contains__(self, key):
+        return dict.__contains__(self, key.lower())
+
+    def __delitem__(self, k):
+        dict.__delitem__(self, k.lower())
+    
+    def has_key(self, key):
+        return dict.has_key(self, key.lower())
+    
+    def get(self, key, def_val=None):
+        return dict.get(self, key.lower(), def_val)
+    
+    def setdefault(self, key, def_val=None):
+        return dict.setdefault(self, key.lower(), def_val)
+    
+    def update(self, other):
+        for k,v in other.items():
+            dict.__setitem__(self, k.lower(), v)
+    
+    def fromkeys(self, iterable, value=None):
+        d = CaselessDict()
+        for k in iterable:
+            dict.__setitem__(d, k.lower(), value)
+        return d
+    
+    def pop(self, key, def_val=None):
+        return dict.pop(self, key.lower(), def_val)
+    
+    def keys(self):
+        return CaselessList(dict.keys(self))
+
+__DEFAULT_FACT_IOR_FILE = "/tmp/rdifact.ior"
+__BASE_LINE             = "notifd"
+__END_NOTIFD_LINE       = "/DEVICE/notifd:"
+__NOTIFD_FACTORY_PREFIX = "notifd/factory/"
+
+def notifd2db(notifd_ior_file=__DEFAULT_FACT_IOR_FILE, files=None, host=None, out=sys.stdout):
+    ior_string = ""
+    with file(notifd_ior_file) as ior_file:
+        ior_string = ior_file.read()
+    
+    if files is None:
+        return _notifd2db_real_db(ior_string, host=host, out=out)
+    else:
+        return _notifd2db_file_db(ior_string, files, out=out)
+
+def _notifd2db_file_db(ior_string, files, out=sys.stdout):
+    raise RuntimeError("Not implemented yet")
+
+    print >>out, "going to export notification service event factory to " \
+                 "device server property file(s) ..."
+    for f in files:
+        with file(f, "w") as out_file:
+            pass
+    return
+
+def _notifd2db_real_db(ior_string, host=None, out=sys.stdout):
+    import PyTango
+    print >>out, "going to export notification service event factory to " \
+                 "Tango database ..."
+                 
+    num_retries = 3
+    while num_retries > 0:
+        try:
+            db = PyTango.Database()
+            db.set_timeout_millis(10000)
+            num_retries = 0
+        except PyTango.DevFailed, df:
+            num_retries -= 1
+            if num_retries == 0:
+                print >>out, "Can't create Tango database object"
+                print >>out, str(df)
+                return
+            print >>out, "Can't create Tango database object, retrying...."
+    
+    if host is None:
+        host_name = socket.getfqdn()
+    
+    global __NOTIFD_FACTORY_PREFIX
+    notifd_factory_name = __NOTIFD_FACTORY_PREFIX + host_name
+    
+    args = notifd_factory_name, ior_string, host_name, str(os.getpid()), "1"
+    
+    num_retries = 3
+    while num_retries > 0:
+        try:
+            ret = db.command_inout("DbExportEvent", args)
+            print >>out, "Successfully exported notification service event " \
+                         "factory for host", host_name, "to Tango database !"
+            break
+        except PyTango.CommunicationFailed, cf:
+            if len(cf.errors) >= 2:
+                if e.errors[1].reason == "API_DeviceTimedOut":
+                    if num_retries > 0:
+                        num_retries -= 1
+                else:
+                    num_retries = 0
+            else:
+                num_retries = 0
+        except Exception, e:
+            num_retries = 0
+    
+    if num_retries == 0:
+        print >>out, "Failed to export notification service event factory " \
+                     "to TANGO database"
diff --git a/PyTango3/__init__.py b/PyTango3/__init__.py
new file mode 100644
index 0000000..f0be582
--- /dev/null
+++ b/PyTango3/__init__.py
@@ -0,0 +1,23 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+from tango3 import *
diff --git a/PyTango3/tango3.py b/PyTango3/tango3.py
new file mode 100644
index 0000000..06c41d8
--- /dev/null
+++ b/PyTango3/tango3.py
@@ -0,0 +1,155 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+from PyTango import *
+
+import PyTango
+PyTango.EventType.CHANGE = PyTango.EventType.CHANGE_EVENT
+PyTango.EventType.QUALITY = PyTango.EventType.QUALITY_EVENT
+PyTango.EventType.PERIODIC = PyTango.EventType.PERIODIC_EVENT
+PyTango.EventType.ARCHIVE = PyTango.EventType.ARCHIVE_EVENT
+PyTango.EventType.USER = PyTango.EventType.USER_EVENT
+PyTango.EventType.DATA_READY = PyTango.EventType.DATA_READY_EVENT
+PyTango.EventType.ATTR_CONF = PyTango.EventType.ATTR_CONF_EVENT
+
+PyUtil = PyTango.Util
+PyDeviceClass = PyTango.DeviceClass
+
+set_attribute_value = PyTango.Attribute.set_value
+set_attribute_value_date_quality = PyTango.Attribute.set_value_date_quality
+
+class AttributeValue(PyTango.DeviceAttribute):
+    pass
+
+__original_DeviceProxy = PyTango.DeviceProxy
+
+class DeviceProxy3(__original_DeviceProxy):
+    defaultCommandExtractAs = ExtractAs.PyTango3
+
+    def __init__(self, *args, **kwds):
+        self.__init_state_status()
+        super(DeviceProxy3, self).__init__(*args, **kwds)
+
+    def __init_state_status(self):
+        if hasattr(self, "State"):
+            if callable(getattr(self, "State")):
+                self.dev_state = self.State
+        if hasattr(self, "Status"):
+            if callable(getattr(self, "Status")):
+                self.dev_status = self.Status
+
+    def write_attribute(self, attr_name, value=None):
+        if isinstance(attr_name, PyTango.DeviceAttribute):
+            if value is not None:
+                raise AttributeError('Using DeviceAttribute as attribute, only one parameter is expected.')
+            da = attr_name
+            attr_name = da.name
+            value = da.value
+        return super(DeviceProxy3, self).write_attribute(attr_name, value)
+
+    def read_attribute(self, attr_name, extract_as=DeviceAttribute.ExtractAs.PyTango3):
+        return super(DeviceProxy3, self).read_attribute(attr_name, extract_as)
+
+    def read_attribute_as_str(self, attr_name):
+        """
+            read_attribute_as_str( (DeviceProxy)self, (str)attr_name ) -> DeviceAttribute :
+                Read a single attribute.
+            Parameters :
+                    - attr_name  : A string, the name of the attribute to read.
+            Return     : a PyTango.DeviceAttribute. It's "value" field will contain
+                        a string representing the raw data sent by Tango.
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from Device
+        """
+        return super(DeviceProxy3, self).read_attribute(attr_name, DeviceAttribute.ExtractAs.String)
+
+
+    def read_attributes(self, attr_names, extract_as=DeviceAttribute.ExtractAs.PyTango3):
+        return super(DeviceProxy3, self).read_attributes(attr_names, extract_as)
+
+    def read_attributes_as_str(self, attr_names):
+        """
+            read_attributes( (DeviceProxy)self, (object)attr_names, (ExtractAs)extract_as) -> object :
+                Read the list of specified attributes.
+            Parameters :
+                    - attr_names : A list of attributes to read. It should
+                                be a StdStringVector or a sequence of str.
+            Return     : a list of PyTango.DeviceAttribute. The "value" field
+                        is just a string representing the raw data.
+
+            Throws     : ConnectionFailed, CommunicationFailed, DevFailed from device
+        """
+        return super(DeviceProxy3, self).read_attribute(attr_names, DeviceAttribute.ExtractAs.String)
+
+
+
+    def write_read_attribute(self, attr_name, value, extract_as=DeviceAttribute.ExtractAs.PyTango3):
+        return super(DeviceProxy3, self).write_read_attribute(attr_name, extract_as)
+
+    def write_read_attribute_as_str(self, args):
+        """
+            write_read_attribute( (DeviceProxy)self, (str)attr_name, (object)values, (ExtractAs)xs) -> object :
+                Write then read a single attribute in a single network call. By
+                default (serialisation by device), the execution of this call in
+                the server can't be interrupted by other clients.
+            Parameters : see write_attribute(attr_name, value)
+            Return     : A PyTango.DeviceAttribute object. See read_attribute_as_str()
+
+            Throws     : ConnectionFailed, CommunicationFailed, DeviceUnlocked, DevFailed from device, WrongData
+            New in PyTango 7.0.0
+        """
+        return super(DeviceProxy3, self).write_read_attribute(attr_name, DeviceAttribute.ExtractAs.String)
+
+
+    def read_attributes_reply(self, idx, timeout=None, extract_as=DeviceAttribute.ExtractAs.PyTango3):
+        if timeout is None:
+            return super(DeviceProxy3, self).read_attributes_reply(idx, extract_as=extract_as)
+        else:
+            return super(DeviceProxy3, self).read_attributes_reply(idx, timeout, extract_as)
+
+    def read_attribute_reply(self, idx, timeout=None, extract_as=DeviceAttribute.ExtractAs.PyTango3):
+        return self.read_attributes_reply(idx, timeout, extract_as)[0]
+
+    def read_attributes_reply_as_str(self, idx, timeout=None):
+        """
+            See read_attributes_reply().
+            The result is given as in read_attributes_as_str().
+            New in PyTango 7.0.0
+        """
+        return self.read_attributes_reply(idx, timeout, extract_as=DeviceAttribute.ExtractAs.String)
+
+    def read_attribute_reply_as_str(self, idx, timeout=None):
+        """
+            New in PyTango 7.0.0
+        """
+        return self.read_attributes_reply_as_str(idx, timeout)[0]
+
+
+def __copy_doc(fnname):
+    getattr(DeviceProxy3, fnname).im_func.__doc__ = getattr(DeviceProxy3.__base__, fnname).im_func.__doc__
+
+__copy_doc('read_attribute')
+__copy_doc('read_attributes')
+__copy_doc('read_attribute_reply')
+__copy_doc('read_attributes_reply')
+
+DeviceProxy = DeviceProxy3
diff --git a/cPyTango/__init__.py b/cPyTango/__init__.py
new file mode 100644
index 0000000..55f9c92
--- /dev/null
+++ b/cPyTango/__init__.py
@@ -0,0 +1 @@
+from cPyTango import *
diff --git a/cPyTango/cPyTango.py b/cPyTango/cPyTango.py
new file mode 100644
index 0000000..4c4b838
--- /dev/null
+++ b/cPyTango/cPyTango.py
@@ -0,0 +1,873 @@
+import ctypes
+import ctypes.util
+import atexit
+import enumeration
+import time
+
+_tango_lib_name = ctypes.util.find_library("c_tango")
+
+if _tango_lib_name is None:
+    raise RuntimeException("Failed to find c_tango shared library")
+
+_ref      = ctypes.byref
+String    = ctypes.c_char_p
+StringPtr = ctypes.POINTER(String)
+Int       = ctypes.c_int
+IntPtr    = ctypes.POINTER(Int) 
+Enum      = ctypes.c_int
+Length    = ctypes.c_uint
+Bool      = ctypes.c_short
+
+c_tango = ctypes.CDLL(_tango_lib_name)
+
+TangoDataType = Enum
+TangoDataTypeEnum = enumeration.Enumeration("TangoDataTypeEnum", (
+    "DEV_VOID",
+    "DEV_BOOLEAN",
+    "DEV_SHORT",
+    "DEV_LONG",
+    "DEV_FLOAT",
+    "DEV_DOUBLE",
+    "DEV_USHORT",
+    "DEV_ULONG",
+    "DEV_STRING",
+    "DEVVAR_CHARARRAY",
+    "DEVVAR_SHORTARRAY",
+    "DEVVAR_LONGARRAY",
+    "DEVVAR_FLOATARRAY",
+    "DEVVAR_DOUBLEARRAY",
+    "DEVVAR_USHORTARRAY",
+    "DEVVAR_ULONGARRAY",
+    "DEVVAR_STRINGARRAY",
+    "DEVVAR_LONGSTRINGARRAY",
+    "DEVVAR_DOUBLESTRINGARRAY",
+    "DEV_STATE",
+    "CONST_DEV_STRING",
+    "DEVVAR_BOOLEANARRAY",
+    "DEV_UCHAR",
+    "DEV_LONG64",
+    "DEV_ULONG64",
+    "DEVVAR_LONG64ARRAY",
+    "DEVVAR_ULONG64ARRAY",
+    "DEV_INT" ) )
+locals().update(TangoDataTypeEnum.lookup)
+TangoDataTypePtr = ctypes.POINTER(TangoDataType)
+
+def _is_scalar(data_type):
+    if data_type <= TangoDataTypeEnum.DEV_STRING: return True
+    if data_type > TangoDataTypeEnum.DEV_STRING and data_type < TangoDataTypeEnum.DEV_STATE: return False
+    if data_type == TangoDataTypeEnum.DEVVAR_BOOLEANARRAY or \
+       data_type == TangoDataTypeEnum.DEVVAR_LONG64ARRAY or \
+       data_type == TangoDataTypeEnum.DEVVAR_ULONG64ARRAY:
+       return False
+    return True
+
+TangoDataTypeEnum.is_scalar = _is_scalar
+
+TangoDevState = Enum
+TangoDevStateEnum = enumeration.Enumeration("TangoDevStateEnum", (
+    "ON",
+    "OFF",
+    "CLOSE",
+    "OPEN",
+    "INSERT",
+    "EXTRACT",
+    "MOVING",
+    "STANDBY",
+    "FAULT",
+    "INIT",
+    "RUNNING",
+    "ALARM",
+    "DISABLE",
+    "UNKNOWN") )
+locals().update(TangoDevStateEnum.lookup)
+TangoDevStatePtr = ctypes.POINTER(TangoDevState)
+
+AttrQuality = Enum
+AttrQualityEnum = enumeration.Enumeration("AttrQualityEnum", (
+    "ATTR_VALID",
+    "ATTR_INVALID",
+    "ATTR_ALARM",
+    "ATTR_CHANGING", 
+    "ATTR_WARNING" ) )
+locals().update(AttrQualityEnum.lookup)
+AttrQualityPtr = ctypes.POINTER(AttrQuality)
+
+AttrWriteType = Enum
+AttrWriteTypeEnum = enumeration.Enumeration("AttrWriteTypeEnum", (
+   "READ",
+   "READ_WITH_WRITE",
+   "WRITE",
+   "READ_WRITE" ) )
+locals().update(AttrWriteTypeEnum.lookup)
+AttrWriteTypePtr = ctypes.POINTER(AttrWriteType)
+
+AttrDataFormat = Enum
+AttrDataFormatEnum = enumeration.Enumeration("AttrDataFormatEnum", (
+    "SCALAR",
+    "SPECTRUM",
+    "IMAGE" ) )
+locals().update(AttrDataFormatEnum.lookup)
+AttrDataFormatPtr = ctypes.POINTER(AttrDataFormat)
+
+DispLevel = Enum
+DispLevelEnum = enumeration.Enumeration("DispLevelEnum", (
+    "OPERATOR",
+    "EXPERT" ) )
+locals().update(DispLevelEnum.lookup)
+DispLevelPtr = ctypes.POINTER(DispLevel)
+
+ErrSeverity = Enum
+ErrSeverityEnum = enumeration.Enumeration("ErrSeverityEnum", (
+   "WARN",
+   "ERR",
+   "PANIC" ) )
+locals().update(ErrSeverityEnum.lookup)   
+ErrSeverityPtr = ctypes.POINTER(ErrSeverity)
+
+DevSource = Enum
+DevSourceEnum = enumeration.Enumeration("DevSourceEnum", (
+    "DEV",
+    "CACHE",
+    "CACHE_DEV" ) )
+locals().update(DevSourceEnum.lookup)  
+DevSourcePtr = ctypes.POINTER(DevSource)
+    
+TangoDevLong = ctypes.c_int32
+TangoDevLongPtr = ctypes.POINTER(TangoDevLong)
+TangoDevULong = ctypes.c_uint32
+TangoDevULongPtr = ctypes.POINTER(TangoDevULong)
+TangoDevLong64 = ctypes.c_int64
+TangoDevLong64Ptr = ctypes.POINTER(TangoDevLong64)
+TangoDevULong64 = ctypes.c_uint64
+TangoDevULong64Ptr = ctypes.POINTER(TangoDevULong64)
+
+
+class VarArray(ctypes.Structure):
+    
+    def __len__(self):
+        return self.length
+    
+    def __getitem__(self, i):
+        if not isinstance(i,int): raise TypeError("tuple indices must be integers")
+        if i < 0 or i > self.length-1: raise IndexError("tuple index out of range")
+        return self.sequence[i]
+
+
+class VarBoolArray(VarArray):
+    _fields_ = \
+        ("length", Length), \
+        ("sequence", ctypes.POINTER(ctypes.c_int16)) 
+        
+
+class VarCharArray(VarArray):
+    _fields_ = \
+        ("length", Length), \
+        ("sequence", ctypes.POINTER(ctypes.c_char)) 
+
+
+class VarShortArray(VarArray):
+    _fields_ = \
+        ("length", Length), \
+        ("sequence", ctypes.POINTER(ctypes.c_int16)) 
+
+
+class VarUShortArray(VarArray):
+    _fields_ = \
+        ("length", Length), \
+        ("sequence", ctypes.POINTER(ctypes.c_uint16)) 
+
+
+class VarLongArray(VarArray):
+    _fields_ = \
+        ("length", Length), \
+        ("sequence", TangoDevLongPtr) 
+
+
+class VarULongArray(VarArray):
+    _fields_ =  \
+        ("length", Length), \
+        ("sequence", TangoDevULongPtr) 
+
+
+class VarLong64Array(VarArray):
+    _fields_ = \
+        ("length", Length), \
+        ("sequence", TangoDevLong64Ptr) 
+
+
+class VarULong64Array(VarArray):
+    _fields_ = \
+        ("length", Length), \
+        ("sequence", TangoDevULong64Ptr) 
+
+
+class VarFloatArray(VarArray):
+    _fields_ = \
+        ("length", Length), \
+        ("sequence", ctypes.POINTER(ctypes.c_float)) 
+
+
+class VarDoubleArray(VarArray):
+    _fields_ =  \
+        ("length", Length), \
+        ("sequence", ctypes.POINTER(ctypes.c_double)) 
+    
+
+class VarStringArray(VarArray):
+    _fields_ = \
+        ("length", Length), \
+        ("sequence", StringPtr)
+    
+    def __str__(self):
+        l = self.length
+        if l == 1:
+            return self.sequence[0]
+        return str(list(seq[:10]))
+VarStringArrayPtr = ctypes.POINTER(VarStringArray)        
+
+class VarStateArray(VarArray):
+    _fields_ = \
+        ("length", Length), \
+        ("sequence", TangoDevStatePtr) 
+    
+    def __str__(self):
+        l = self.length
+        if l == 1:
+            return TangoDevStateEnum.whatis(self.sequence[0])
+        return map(cPyTango.TangoDevStateEnum.whatis, seq[:10])
+        
+
+class TangoAttributeData(ctypes.Union):
+    _fields_ =  \
+        ("bool_arr", VarBoolArray), \
+        ("char_arr", VarCharArray), \
+        ("short_arr", VarShortArray), \
+        ("ushort_arr", VarUShortArray), \
+        ("long_arr", VarLongArray), \
+        ("ulong_arr", VarULongArray), \
+        ("long64_arr", VarLong64Array), \
+        ("ulong64_arr", VarULong64Array), \
+        ("float_arr", VarFloatArray), \
+        ("double_arr", VarDoubleArray), \
+        ("string_arr", VarStringArray), \
+        ("state_arr", VarStateArray)
+    
+    def get_raw(self, type):
+        if type == DEV_BOOLEAN:   return self.bool_arr
+        elif type == DEV_UCHAR:    return self.char_arr
+        elif type == DEV_SHORT:   return self.short_arr
+        elif type == DEV_USHORT:  return self.ushort_arr
+        elif type == DEV_LONG:    return self.long_arr
+        elif type == DEV_ULONG:   return self.ulong_arr
+        elif type == DEV_LONG64:  return self.long64_arr
+        elif type == DEV_ULONG64: return self.ulong64_arr
+        elif type == DEV_FLOAT:   return self.float_arr
+        elif type == DEV_DOUBLE:  return self.double_arr
+        elif type == DEV_STRING:  return self.string_arr
+        elif type == DEV_STATE:   return self.state_arr
+
+    def get(self, type):
+        raw = self.get_raw(type)
+        if TangoDataTypeEnum.is_scalar(type):
+            return raw[0]
+        return raw
+
+    def representation(self, type):
+        return str(self.get_raw(type))
+TangoAttributeDataPtr = ctypes.POINTER(TangoAttributeData)
+
+
+class TangoCommandData(ctypes.Union):
+    _fields_ = \
+        ("bool_val", Bool), \
+        ("short_val", ctypes.c_short), \
+        ("ushort_val", ctypes.c_ushort), \
+        ("long_val", ctypes.c_int32), \
+        ("ulong_val", ctypes.c_uint32), \
+        ("float_val", ctypes.c_float), \
+        ("double_val", ctypes.c_double), \
+        ("string_val", ctypes.c_char_p), \
+        ("state_val", TangoDevState), \
+        ("long64_val", ctypes.c_int64), \
+        ("ulong64_val", ctypes.c_uint64), \
+        ("bool_arr", VarBoolArray), \
+        ("char_arr", VarCharArray), \
+        ("short_arr", VarShortArray), \
+        ("ushort_arr", VarUShortArray), \
+        ("long_arr", VarLongArray), \
+        ("ulong_arr", VarULongArray), \
+        ("long64_arr", VarLong64Array), \
+        ("ulong64_arr", VarULong64Array), \
+        ("float_arr", VarFloatArray), \
+        ("double_arr", VarDoubleArray), \
+        ("string_arr", VarStringArray), \
+        ("state_arr", VarStateArray),
+TangoCommandDataPtr = ctypes.POINTER(TangoCommandData)
+
+
+class TangoPropertyData(ctypes.Union):
+    _fields_ = \
+        ("bool_val", Bool), \
+        ("char_val", ctypes.c_char), \
+        ("short_val", ctypes.c_short), \
+        ("ushort_val", ctypes.c_ushort), \
+        ("long_val", ctypes.c_int32), \
+        ("ulong_val", ctypes.c_uint32), \
+        ("float_val", ctypes.c_float), \
+        ("double_val", ctypes.c_double), \
+        ("string_val", ctypes.c_char_p), \
+        ("long64_val", ctypes.c_int64), \
+        ("ulong64_val", ctypes.c_uint64), \
+        ("short_arr", VarShortArray), \
+        ("ushort_arr", VarUShortArray), \
+        ("long_arr", VarLongArray), \
+        ("ulong_arr", VarULongArray), \
+        ("long64_arr", VarLong64Array), \
+        ("ulong64_arr", VarULong64Array), \
+        ("float_arr", VarFloatArray), \
+        ("double_arr", VarDoubleArray), \
+        ("string_arr", VarStringArray),
+TangoPropertyDataPtr = ctypes.POINTER(TangoPropertyData)
+
+
+class CommandData(ctypes.Structure):
+    _fields_ = \
+        ("arg_type",TangoDataType), \
+        ("cmd_data",TangoCommandData)
+CommandDataPtr = ctypes.POINTER(CommandData)
+
+
+_time_t = ctypes.c_long
+_suseconds_t = ctypes.c_long
+
+class timeval(ctypes.Structure):
+    _fields_ = \
+        ("tv_sec", _time_t), \
+        ("tv_usec", _suseconds_t),
+    
+    def __str__(self):
+        return time.ctime(self.tv_sec + 1E-6 * self.tv_usec)
+timevalPtr = ctypes.POINTER(timeval)
+
+
+class AttributeData(ctypes.Structure):
+    _fields_ = \
+        ("data_type", TangoDataType), \
+        ("attr_data", TangoAttributeData), \
+        ("quality", AttrQuality), \
+        ("name", String), \
+        ("dim_x", Int), \
+        ("dim_y", Int), \
+        ("time_stamp", timeval)
+    
+    def __str__(self):
+        s = "AttributeData[\n"
+        s += "name: %s\n" % self.name
+        s += "data_type: %s\n" % TangoDataTypeEnum.whatis(self.data_type)
+        s += "quality: %s\n" % AttrQualityEnum.whatis(self.quality)
+        s += "dim_x: %d\n" % self.dim_x
+        s += "dim_y: %d\n" % self.dim_y
+        s += "time_stamp: %s\n" % self.time_stamp
+        s += "attr_data: %s\n" % str(self.attr_data.representation(self.data_type))
+        s += "]\n"
+        return s
+    
+    def get_raw_data(self):
+        return self.attr_data.get_raw(self.data_type)
+
+    def get_data(self):
+        return self.attr_data.get(self.data_type)
+AttributeDataPtr = ctypes.POINTER(AttributeData)
+
+
+class AttributeDataList(ctypes.Structure):
+    _fields_ = \
+        ("length", Length), \
+        ("sequence", AttributeDataPtr)
+
+    def __len__(self):
+        return self.length
+    
+    def __getitem__(self, i):
+        if not isinstance(i,int): raise TypeError("tuple indices must be integers")
+        if i < 0 or i > self.length-1: raise IndexError("tuple index out of range")
+        return self.sequence[i]
+    
+    def __str__(self):
+        s = "AttributeDataList[\n"
+        for attr in self: s += attr
+        return s
+AttributeDataListPtr = ctypes.POINTER(AttributeDataList)
+
+                        
+class DevFailed(ctypes.Structure):
+    _fields_ = \
+        ("desc", String), \
+        ("reason", String), \
+        ("origin", String), \
+        ("severity", ErrSeverity)
+    
+    def __str__(self):
+        s  = "Severity    : %d\n" % self.severity
+        s += "Reason      : %s\n" % self.reason
+        s += "Description : %s\n" % self.desc
+        s += "Origin      : %s\n\n" % self.origin
+        return s    
+
+    def __repr__(self):
+        return self.__str__()
+DevFailedPtr = ctypes.POINTER(DevFailed)
+
+
+class ErrorStack(ctypes.Structure):
+    _fields_ = \
+        ("length", Length), \
+        ("sequence", DevFailedPtr) 
+
+    def __len__(self):
+        return self.length
+    
+    def __getitem__(self, i):
+        if not isinstance(i,int): raise TypeError("tuple indices must be integers")
+        if i < 0 or i > self.length-1: raise IndexError("tuple index out of range")
+        return self.sequence[i]
+    
+    def __str__(self):
+        s = "\nTango exception:\n"
+        for i in xrange(self.length):
+            s += str(self.sequence[i])
+        return s
+        
+    def __repr__(self):
+        return self.__str__()
+ErrorStackPtr = ctypes.POINTER(ErrorStack)
+
+
+class CommandInfo(ctypes.Structure):
+    _fields_ = \
+        ("cmd_name", String), \
+        ("cmd_tag", Int), \
+        ("in_type", Int), \
+        ("out_type", Int), \
+        ("in_type_desc", String), \
+        ("out_type_desc", String), \
+        ("disp_level", DispLevel) 
+CommandInfoPtr = ctypes.POINTER(CommandInfo)
+
+
+class CommandInfoList(ctypes.Structure):
+    _fields_ = \
+        ("length", Length), \
+        ("sequence", CommandInfoPtr)
+CommandInfoListPtr = ctypes.POINTER(CommandInfoList)
+
+
+class AttributeInfo(ctypes.Structure):
+    _fields_ = \
+        ("name", String), \
+        ("writable", AttrWriteType), \
+        ("data_format", AttrDataFormat), \
+        ("data_type", TangoDataType), \
+        ("max_dim_x", Int), \
+        ("max_dim_y", Int), \
+        ("description", String), \
+        ("label", String), \
+        ("unit", String), \
+        ("standard_unit", String), \
+        ("display_unit", String), \
+        ("format", String), \
+        ("min_value", String), \
+        ("max_value", String), \
+        ("min_alarm", String), \
+        ("max_alarm", String), \
+        ("writable_attr_name", String), \
+        ("disp_level", DispLevel)
+AttributeInfoPtr = ctypes.POINTER(AttributeInfo)
+
+
+class AttributeInfoList(ctypes.Structure):
+    _fields_ = \
+        ("length", Length), \
+        ("sequence", AttributeInfoPtr)
+AttributeInfoListPtr = ctypes.POINTER(AttributeInfoList)
+
+
+class DbDatum(ctypes.Structure):
+    _fields_ = \
+        ("property_name", String), \
+        ("data_type", TangoDataType), \
+        ("prop_data", TangoPropertyData), \
+        ("is_empty", Bool), \
+        ("wrong_data_type", Bool)
+DbDatumPtr = ctypes.POINTER(DbDatum)
+
+
+class DbData(ctypes.Structure):
+    _fields_ = \
+        ("length", Length), \
+        ("sequence", DbDatumPtr)
+DbDataPtr = ctypes.POINTER(DbData)
+
+
+DeviceProxyPtr    = ctypes.c_void_p
+DeviceProxyPtrPtr = ctypes.POINTER(DeviceProxyPtr)
+DatabasePtr       = ctypes.c_void_p
+DatabasePtrPtr    = ctypes.POINTER(DatabasePtr)
+
+
+c_tango.tango_create_device_proxy.argtypes = (String, DeviceProxyPtrPtr, ErrorStackPtr, )
+c_tango.tango_delete_device_proxy.argtypes = (DeviceProxyPtrPtr, ErrorStackPtr, )
+c_tango.tango_set_timeout_millis.argtypes = (DeviceProxyPtr, Int, ErrorStackPtr, )
+c_tango.tango_get_timeout_millis.argtypes = (DeviceProxyPtr, IntPtr, ErrorStackPtr, )
+c_tango.tango_set_source.argtypes = (DeviceProxyPtr, DevSource, ErrorStackPtr, )
+c_tango.tango_get_source.argtypes = (DeviceProxyPtr, DevSourcePtr, ErrorStackPtr, )
+c_tango.tango_command_query.argtypes = (DeviceProxyPtr, String, CommandInfoPtr, ErrorStackPtr, )
+c_tango.tango_command_list_query.argtypes = (DeviceProxyPtr, CommandInfoListPtr, ErrorStackPtr, )
+c_tango.tango_command_inout.argtypes = (DeviceProxyPtr, String, CommandDataPtr, CommandDataPtr, ErrorStackPtr, )
+c_tango.tango_free_CommandData.argtypes = (CommandDataPtr, )
+c_tango.tango_free_CommandInfo.argtypes = (CommandInfoPtr, )
+c_tango.tango_free_CommandInfoList.argtypes = (CommandInfoListPtr, )
+c_tango.tango_get_attribute_list.argtypes = (DeviceProxyPtr, VarStringArrayPtr, ErrorStackPtr, )
+c_tango.tango_get_attribute_config.argtypes = (DeviceProxyPtr, VarStringArrayPtr, AttributeInfoListPtr, ErrorStackPtr, )
+c_tango.tango_attribute_list_query.argtypes = (DeviceProxyPtr, AttributeInfoListPtr, ErrorStackPtr, )
+c_tango.tango_read_attribute.argtypes = (DeviceProxyPtr, String, AttributeDataPtr, ErrorStackPtr, )
+c_tango.tango_write_attribute.argtypes = (DeviceProxyPtr, String, AttributeDataPtr, ErrorStackPtr, )
+c_tango.tango_read_attributes.argtypes = (DeviceProxyPtr, VarStringArrayPtr, AttributeDataListPtr, ErrorStackPtr, )
+c_tango.tango_write_attributes.argtypes = (DeviceProxyPtr, AttributeDataListPtr, ErrorStackPtr, )
+c_tango.tango_free_AttributeData.argtypes = (AttributeDataPtr, )
+c_tango.tango_free_AttributeDataList.argtypes = (AttributeDataListPtr, )
+c_tango.tango_free_VarStringArray.argtypes = (VarStringArrayPtr, )
+c_tango.tango_print_ErrorStack.argtypes = (ErrorStackPtr, )
+c_tango.tango_free_ErrorStack.argtypes = (ErrorStackPtr, )
+c_tango.tango_create_database_proxy.argtypes = (DatabasePtrPtr, ErrorStackPtr, )
+c_tango.tango_delete_database_proxy.argtypes = (DatabasePtrPtr, ErrorStackPtr, )
+c_tango.tango_get_device_exported.argtypes = (DatabasePtr, String, DbDatumPtr, ErrorStackPtr, )
+c_tango.tango_get_device_exported_for_class.argtypes = (DatabasePtr, String, DbDatumPtr, ErrorStackPtr, )
+c_tango.tango_get_object_list.argtypes = (DatabasePtr, String, DbDatumPtr, ErrorStackPtr, )
+c_tango.tango_get_object_property_list.argtypes = (DatabasePtr, String, String, DbDatumPtr, ErrorStackPtr, )
+c_tango.tango_get_property.argtypes = (DatabasePtr, String, DbDataPtr, ErrorStackPtr, )
+c_tango.tango_put_property.argtypes = (DatabasePtr, String, DbDataPtr, ErrorStackPtr, )
+c_tango.tango_delete_property.argtypes = (DatabasePtr, String, DbDataPtr, ErrorStackPtr, )
+c_tango.tango_get_device_property.argtypes = (DeviceProxyPtr, DbDataPtr, ErrorStackPtr, )
+c_tango.tango_put_device_property.argtypes = (DeviceProxyPtr, DbDataPtr, ErrorStackPtr, )
+c_tango.tango_delete_device_property.argtypes = (DeviceProxyPtr, DbDataPtr, ErrorStackPtr, )
+c_tango.tango_free_DbDatum.argtypes = (DbDatumPtr, )
+c_tango.tango_free_DbData.argtypes = (DbDataPtr, )
+
+
+def tango_create_device_proxy(dev_name):
+    dev_name = ctypes.create_string_buffer(dev_name)
+    dev_ptr = ctypes.c_void_p()
+    err_stack = ErrorStack()
+    result = c_tango.tango_create_device_proxy(dev_name, _ref(dev_ptr), _ref(err_stack))
+    if result:
+        return dev_ptr
+    raise Exception(err_stack)
+
+def tango_delete_device_proxy(dev_ptr):
+    err_stack = ErrorStack()
+    result = c_tango.tango_delete_device_proxy(_ref(dev_ptr), _ref(err_stack))
+    if result:
+        return True
+    raise Exception(err_stack)
+
+def tango_set_timeout_millis(dev_ptr, millis):
+    err_stack = ErrorStack()
+    millis = ctypes.c_int(millis)
+    result = c_tango.tango_set_timeout_millis(dev_ptr, millis, _ref(err_stack))
+    if result:
+        return True
+    raise Exception(err_stack)    
+
+def tango_get_timeout_millis(dev_ptr):
+    err_stack = ErrorStack()
+    millis = ctypes.c_int()
+    result = c_tango.tango_get_timeout_millis(dev_ptr, _ref(millis), _ref(err_stack))
+    if result:
+        return millis
+    raise Exception(err_stack)      
+
+def tango_set_source(dev_ptr, src):
+    """src -> DevSource"""
+    err_stack = ErrorStack()
+    result = c_tango.tango_set_source(dev_ptr, src, _ref(err_stack))
+    if result:
+        return True
+    raise Exception(err_stack)   
+    
+def tango_get_source(dev_ptr):
+    err_stack = ErrorStack()
+    src = ctypes.c_int()
+    result = c_tango.tango_get_source(dev_ptr, _ref(src), _ref(err_stack))
+    if result:
+        return src
+    raise Exception(err_stack)
+    
+def tango_command_query(dev_ptr, cmd_name):
+    err_stack = ErrorStack()
+    cmd_name = ctypes.create_string_buffer(cmd_name)
+    cmd_info = CommandInfo()
+    result = c_tango.tango_command_query(dev_ptr, cmd_name, _ref(cmd_info), _ref(err_stack))
+    if result:
+        return cmd_info
+    raise Exception(err_stack)    
+
+def tango_command_list_query(dev_ptr):
+    err_stack = ErrorStack()
+    cmd_info_list = CommandInfoList()
+    result = c_tango.tango_command_list_query(dev_ptr, _ref(cmd_info_list), _ref(err_stack))
+    if result:
+        return cmd_info_list
+    raise Exception(err_stack)    
+
+def tango_command_inout(dev_ptr, cmd_name, arg_in):
+    """arg_in->CommandData"""
+    err_stack = ErrorStack()
+    cmd_name = ctypes.create_string_buffer(cmd_name)
+    arg_out = CommandData()
+    result = c_tango.tango_command_inout(dev_ptr, cmd_name, _ref(arg_in), _ref(arg_out), _ref(err_stack))
+    if result:
+        return arg_out
+    raise Exception(err_stack)  
+    
+def tango_free_CommandData(cmd_data):
+    c_tango.tango_free_CommandData(_ref(cmd_data))
+
+def tango_free_CommandInfo(cmd_info):
+    c_tango.tango_free_CommandInfo(_ref(cmd_info))
+    
+def tango_free_CommandInfoList(cmd_info_list):
+    c_tango.tango_free_CommandInfoList(_ref(cmd_info_list))
+
+def tango_get_attribute_list(dev_ptr):
+    err_stack = ErrorStack()
+    attr_names = VarStringArray()
+    result = c_tango.tango_get_attribute_list(dev_ptr, _ref(attr_names), _ref(err_stack))
+    if result:
+        return attr_names
+    raise Exception(err_stack)  
+    
+def tango_get_attribute_config(dev_ptr, attr_names):
+    print "TODO"
+    return
+    err_stack = ErrorStack()
+    attr_names = VarStringArray()
+    attr_info_list = AttributeInfoList()
+    result = c_tango.tango_get_attribute_config(dev_ptr, _ref(attr_names), _ref(attr_info_list), _ref(err_stack))
+    if result:
+        return attr_info_list
+    raise Exception(err_stack)  
+    
+def tango_attribute_list_query(dev_ptr):
+    err_stack = ErrorStack()
+    attr_info_list = AttributeInfoList()
+    result = c_tango.tango_attribute_list_query(dev_ptr, _ref(attr_info_list), _ref(err_stack))
+    if result:
+        return attr_info_list
+    raise Exception(err_stack) 
+    
+def tango_read_attribute(dev_ptr, attr_name):
+    attr_name = ctypes.create_string_buffer(attr_name)
+    attr_data = AttributeData()
+    err_stack = ErrorStack()
+    result = c_tango.tango_read_attribute(dev_ptr, attr_name, _ref(attr_data), _ref(err_stack))    
+    if result:
+        return attr_data
+    raise Exception(err_stack)
+
+def tango_write_attribute(dev_ptr, attr_name, value):
+    print "TODO"
+    return
+    attr_data = AttributeData()
+    attr_data.name = ctypes.create_string_buffer(attr_name)
+    attr_data.attr_data = value
+    err_stack = ErrorStack()
+    result = c_tango.tango_write_attribute(dev_ptr, attr_name, _ref(attr_data), _ref(err_stack))    
+    if result:
+        return True
+    raise Exception(err_stack)
+
+def tango_read_attributes(dev_ptr, attr_names):
+    print "TODO"
+    return
+    attr_data_list = AttributeDataList()
+    attr_names = VarStringArray()
+    err_stack = ErrorStack()
+    result = c_tango.tango_read_attribute(dev_ptr, _ref(attr_names), _ref(attr_data_list), _ref(err_stack))    
+    if result:
+        return attr_data
+    raise Exception(err_stack)
+    
+def tango_write_attributes(dev_ptr, attr_data_list):
+    """attr_data_list->AttributeDataList"""
+    err_stack = ErrorStack()
+    result = c_tango.tango_write_attributes(dev_ptr, _ref(attr_data_list), _ref(err_stack))    
+    if result:
+        return True
+    raise Exception(err_stack)
+    
+def tango_free_AttributeData(attr_data):
+    c_tango.tango_free_AttributeData(_ref(attr_data))
+    
+def tango_free_AttributeDataList(attr_data_list):
+    c_tango.tango_free_AttributeDataList(_ref(attr_data_list))
+    
+def tango_free_VarStringArray(str_array):
+    c_tango.tango_free_VarStringArray(_ref(str_array))
+
+def tango_print_ErrorStack(err_stack):
+    """Should not be used. This function prints to STDOUT instead of sys.stdout.
+       Use: 'print err_stack' instead"""
+    c_tango.tango_print_ErrorStack(_ref(err_stack))
+
+def tango_free_ErrorStack(err_stack):
+    c_tango.tango_free_ErrorStack(_ref(err_stack))
+
+def tango_create_database_proxy():
+    err_stack = ErrorStack()
+    db_ptr = ctypes.c_void_p()
+    result = c_tango.tango_create_database_proxy(_ref(db_ptr), _ref(err_stack))    
+    if result:
+        return db_ptr
+    raise Exception(err_stack)
+
+def tango_delete_database_proxy(db_ptr):
+    err_stack = ErrorStack()
+    result = c_tango.tango_delete_database_proxy(_ref(db_ptr), _ref(err_stack))    
+    if result:
+        return True
+    raise Exception(err_stack)
+
+def tango_get_device_exported(db_ptr, name_filter):
+    err_stack = ErrorStack()
+    name_filter = ctypes.create_string_buffer(name_filter)
+    db_datum = DbDatum()
+    result = c_tango.tango_get_device_exported(db_ptr, name_filter, _ref(db_datum), _ref(err_stack))    
+    if result:
+        return db_datum
+    raise Exception(err_stack)
+
+def tango_get_device_exported_for_class(db_ptr, class_name):
+    err_stack = ErrorStack()
+    class_name = ctypes.create_string_buffer(class_name)
+    db_datum = DbDatum()
+    result = c_tango.tango_get_device_exported_for_class(db_ptr, class_name, _ref(db_datum), _ref(err_stack))    
+    if result:
+        return db_datum
+    raise Exception(err_stack)
+
+def tango_get_object_list(db_ptr, name_filter):
+    err_stack = ErrorStack()
+    name_filter = ctypes.create_string_buffer(name_filter)
+    db_datum = DbDatum()
+    result = c_tango.tango_get_object_list(db_ptr, name_filter, _ref(db_datum), _ref(err_stack))    
+    if result:
+        return db_datum
+    raise Exception(err_stack)
+
+def tango_get_object_property_list(db_ptr, obj_name, name_filter):
+    err_stack = ErrorStack()
+    obj_name = ctypes.create_string_buffer(obj_name)
+    name_filter = ctypes.create_string_buffer(name_filter)
+    db_datum = DbDatum()
+    result = c_tango.tango_get_object_property_list(db_ptr, obj_name, name_filter, _ref(db_datum), _ref(err_stack))    
+    if result:
+        return db_datum
+    raise Exception(err_stack)
+
+def tango_get_property(db_ptr, obj_name):
+    err_stack = ErrorStack()
+    obj_name = ctypes.create_string_buffer(obj_name)
+    db_data = DbData()
+    result = c_tango.tango_get_property(db_ptr, obj_name, _ref(db_data), _ref(err_stack))    
+    if result:
+        return db_datum
+    raise Exception(err_stack)
+
+def tango_put_property(db_ptr, obj_name, prop_list):
+    """prop_list -> DbData"""
+    err_stack = ErrorStack()
+    obj_name = ctypes.create_string_buffer(obj_name)
+    result = c_tango.tango_put_property(db_ptr, obj_name, _ref(prop_list), _ref(err_stack))    
+    if result:
+        return True
+    raise Exception(err_stack)
+
+def tango_delete_property(db_ptr, obj_name, prop_list):
+    """prop_list -> DbData"""
+    err_stack = ErrorStack()
+    obj_name = ctypes.create_string_buffer(obj_name)
+    result = c_tango.tango_delete_property(db_ptr, obj_name, _ref(prop_list), _ref(err_stack))    
+    if result:
+        return True
+    raise Exception(err_stack)
+    
+def tango_get_device_property(dev_ptr, prop_list):
+    """prop_list -> DbData"""
+    err_stack = ErrorStack()
+    result = c_tango.tango_get_device_property(dev_ptr, _ref(prop_list), _ref(err_stack))    
+    if result:
+        return prop_list
+    raise Exception(err_stack)
+
+def tango_put_device_property(dev_ptr, prop_list):
+    """prop_list -> DbData"""
+    err_stack = ErrorStack()
+    result = c_tango.tango_put_device_property(dev_ptr, _ref(prop_list), _ref(err_stack))    
+    if result:
+        return True
+    raise Exception(err_stack)
+
+def tango_delete_device_property(dev_ptr, prop_list):
+    """prop_list -> DbData"""
+    err_stack = ErrorStack()
+    result = c_tango.tango_delete_device_property(dev_ptr, _ref(prop_list), _ref(err_stack))    
+    if result:
+        return True
+    raise Exception(err_stack)
+
+def tango_free_DbDatum(db_datum):
+    c_tango.tango_free_DbDatum(_ref(db_datum))
+    
+def tango_free_DbData(db_data):
+    c_tango.tango_free_DbData(_ref(db_data))
+
+
+class DeviceProxy:
+    def __init__(self, dev_name):
+        self._dev_name = dev_name
+        self._dev = tango_create_device_proxy(dev_name)
+        
+    def read_attribute(self, attr_name):
+        return tango_read_attribute(self._dev, attr_name)
+
+    def write_attribute(self, attr_name, value):
+        return tango_read_attribute(self._dev, attr)
+        
+    def read_attributes(self, attr_name_list):
+        return tango_read_attributes(self._dev, attr_name_list)
+        
+    def get_property(self, attr_name_list):
+        if isinstance(attr_name_list, str):
+            attr_name_list = [ attr_name_list ]
+        n = len(attr_name_list)
+        db_data = DbData()
+        db_data.length = n
+        db_data.sequence = (n*DbDatum)()
+        for i in xrange(n):
+            db_data.sequence[i].property_name = attr_name_list[i]
+            db_data.sequence[i].data_type = DEV_STRING
+        return tango_get_device_property(self._dev, db_data)
+
+    def __del__(self):
+        try:
+            if self._dev:
+                try:
+                    tango_delete_device_proxy(self._dev)
+                except Exception, e:
+                    print e
+        except AttributeError:
+            #The error was in the constructor and therefore _dev is not defined
+            pass
+
diff --git a/cPyTango/enumeration.py b/cPyTango/enumeration.py
new file mode 100644
index 0000000..c999114
--- /dev/null
+++ b/cPyTango/enumeration.py
@@ -0,0 +1,86 @@
+import types
+
+""" 
+  Enumeration module.
+  In C, enums allow you to declare a bunch of constants with unique values,
+  without necessarily specifying the actual values (except in cases where you
+  need to). Python has an accepted idiom that's fine for very small numbers of
+  constants (A, B, C, D = range(4)) but it doesn't scale well to large numbers,
+  and it doesn't allow you to specify values for some constants while leaving
+  others unspecified. This approach does those things, while verifying that all
+  values (specified and unspecified) are unique. Enum values then are attributes
+  of an Enumeration class (Volkswagen.BEETLE, Volkswagen.PASSAT, etc.).
+"""
+    
+
+class Enumeration:
+    """ Enumeration class intended to provide the 'enum' feature present in many 
+        programming languages.
+        Usage:
+        car = ThingWithType(Volkswagen.BEETLE)
+        print whatkind(car.type, Volkswagen)
+        bug = ThingWithType(Insect.BEETLE)
+        print whatkind(bug.type, Insect)
+
+        Notice that car's and bug's attributes don't include any of the
+        enum machinery, because that machinery is all CLASS attributes and
+        not INSTANCE attributes. So you can generate thousands of cars and
+        bugs with reckless abandon, never worrying that time or memory will
+        be wasted on redundant copies of the enum stuff.
+
+        print car.__dict__
+        print bug.__dict__
+        pprint.pprint(Volkswagen.__dict__)
+        pprint.pprint(Insect.__dict__)
+        """
+        
+    def __init__(self, name, enumList):
+        self.__doc__ = name
+        lookup = { }
+        reverseLookup = { }
+        uniqueNames = [ ]
+        self._uniqueValues = uniqueValues = [ ]
+        self._uniqueId = 0
+        for x in enumList:
+            if type(x) == types.TupleType:
+                x, i = x
+                if type(x) != types.StringType:
+                    raise EnumException, "enum name is not a string: " + x
+                if type(i) != types.IntType:
+                    raise EnumException, "enum value is not an integer: " + i
+                if x in uniqueNames:
+                    raise EnumException, "enum name is not unique: " + x
+                if i in uniqueValues:
+                    raise EnumException, "enum value is not unique for " + x
+                uniqueNames.append(x)
+                uniqueValues.append(i)
+                lookup[x] = i
+                reverseLookup[i] = x
+        for x in enumList:
+            if type(x) != types.TupleType:
+                if type(x) != types.StringType:
+                    raise EnumException, "enum name is not a string: " + x
+                if x in uniqueNames:
+                    raise EnumException, "enum name is not unique: " + x
+                uniqueNames.append(x)
+                i = self.generateUniqueId()
+                uniqueValues.append(i)
+                lookup[x] = i
+                reverseLookup[i] = x
+        self.lookup = lookup
+        self.reverseLookup = reverseLookup
+   
+    def generateUniqueId(self):
+        while self._uniqueId in self._uniqueValues:
+            self._uniqueId += 1
+        n = self._uniqueId
+        self._uniqueId += 1
+        return n
+    
+    def __getattr__(self, attr):
+        if not self.lookup.has_key(attr):
+            raise AttributeError
+        return self.lookup[attr]
+    
+    def whatis(self, value):
+        return self.reverseLookup[value]
diff --git a/doc/WINDOWS-COMPILATION-EXAMPLE.TXT b/doc/WINDOWS-COMPILATION-EXAMPLE.TXT
new file mode 100644
index 0000000..877ac65
--- /dev/null
+++ b/doc/WINDOWS-COMPILATION-EXAMPLE.TXT
@@ -0,0 +1,38 @@
+
+REM Set environment variables needed to compile
+
+set TANGO_ROOT=C:\Program Files\tango\win32_vc8\win32_dll
+set BOOST_ROOT=C:\Program Files\boost\boost_1_38
+set OMNI_ROOT=%TANGO_ROOT%
+set NUMPY_ROOT=C:\sicilia\Python25\Lib\site-packages\numpy\core\
+
+dir "%OMNI_ROOT%"\lib
+dir "%BOOST_ROOT%\lib"
+
+
+
+REM For some reason distutils is trying to locate Vs9 tools...
+REM And obviously it fails. We will fool him with this:
+
+set VS90COMNTOOLS=%VS80COMNTOOLS%
+
+REM compile :)
+setup.py -v build
+
+
+
+
+
+
+
+REM ------------------------------------
+
+REM to compile:
+setup.py -v build
+
+REM to create a MSI windows installer:
+setup.py bdist_msi
+
+REM to create a EXE windows installer:
+setup.py bdist_wininst
+
diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html
new file mode 100644
index 0000000..ed3d08e
--- /dev/null
+++ b/doc/_templates/layout.html
@@ -0,0 +1,10 @@
+{% extends "sphinxdoc/layout.html" %}
+
+{% block rootrellink %}
+    <li><a href="{{ pathto('index') }}">home</a>| </li>
+    <li><a href="{{ pathto('start') }}">getting started</a>| </li>
+    <li><a href="{{ pathto('quicktour') }}">quick tour</a>| </li>
+    <li><a href="{{ pathto('contents') }}">documentation </a> »</li>
+{% endblock %}
+
+
diff --git a/doc/api.rst b/doc/api.rst
new file mode 100644
index 0000000..e964fa1
--- /dev/null
+++ b/doc/api.rst
@@ -0,0 +1,16 @@
+
+.. currentmodule:: PyTango
+
+.. _api:
+
+===========
+PyTango API
+===========
+
+.. toctree::
+    :maxdepth: 2
+
+    client/index
+    database
+    server/index
+    exception
diff --git a/doc/client/attribute_proxy.rst b/doc/client/attribute_proxy.rst
new file mode 100644
index 0000000..158ed18
--- /dev/null
+++ b/doc/client/attribute_proxy.rst
@@ -0,0 +1,11 @@
+AttributeProxy
+--------------
+
+.. currentmodule:: PyTango
+
+.. autoclass:: PyTango.AttributeProxy
+    :members:
+
+
+
+
diff --git a/doc/client/device_proxy.rst b/doc/client/device_proxy.rst
new file mode 100644
index 0000000..8c617b7
--- /dev/null
+++ b/doc/client/device_proxy.rst
@@ -0,0 +1,9 @@
+.. currentmodule:: PyTango
+
+DeviceProxy
+-----------
+
+.. autoclass:: PyTango.DeviceProxy
+    :show-inheritance: 
+    :members:
+    :inherited-members:
diff --git a/doc/client/group.rst b/doc/client/group.rst
new file mode 100644
index 0000000..f86fc6a
--- /dev/null
+++ b/doc/client/group.rst
@@ -0,0 +1,46 @@
+
+Group
+-----
+
+.. currentmodule:: PyTango
+
+
+.. GroupElement is the base class of Group, but is not the base of
+   anything else. So, I don't include it in the documentation but just
+   add its functions into Group by using :inherited-members:
+
+Group class
+~~~~~~~~~~~
+
+.. autoclass:: PyTango.Group
+    :show-inheritance:
+    :inherited-members:
+    :members:
+
+
+GroupReply classes
+~~~~~~~~~~~~~~~~~~
+
+Group member functions do not return the same as their DeviceProxy counterparts,
+but objects that contain them. This is:
+    - *write attribute* family returns PyTango.GroupReplyList
+    - *read attribute* family returns PyTango.GroupAttrReplyList
+    - *command inout* family returns PyTango.GroupCmdReplyList
+
+The Group*ReplyList objects are just list-like objects containing
+:class:`~PyTango.GroupReply`, :class:`~PyTango.GroupAttrReply` and
+:class:`~GroupCmdReply` elements that will be described now.
+
+Note also that GroupReply is the base of GroupCmdReply and GroupAttrReply.
+
+.. autoclass:: PyTango.GroupReply
+    :members:
+
+.. autoclass:: PyTango.GroupAttrReply
+    :show-inheritance:
+    :members:
+
+.. autoclass:: GroupCmdReply
+    :show-inheritance:
+    :members:
+
diff --git a/doc/client/index.rst b/doc/client/index.rst
new file mode 100644
index 0000000..b2af241
--- /dev/null
+++ b/doc/client/index.rst
@@ -0,0 +1,11 @@
+The Tango Device Python API
+===========================
+
+.. toctree::
+    :maxdepth: 2
+
+    device_proxy
+    attribute_proxy
+    group
+    miscellaneous
+    other
diff --git a/doc/client/miscellaneous.rst b/doc/client/miscellaneous.rst
new file mode 100644
index 0000000..18870a6
--- /dev/null
+++ b/doc/client/miscellaneous.rst
@@ -0,0 +1,144 @@
+
+
+.. currentmodule:: PyTango
+
+API util
+--------
+
+.. autoclass:: PyTango.ApiUtil
+    :members:
+
+Information classes
+-------------------
+
+See also `Event configuration information`_
+
+Attribute
+~~~~~~~~~
+.. autoclass:: PyTango.AttributeAlarmInfo
+    :members:
+
+.. autoclass:: PyTango.AttributeDimension
+    :members:
+
+.. autoclass:: PyTango.AttributeInfo
+    :members:
+
+.. autoclass:: PyTango.AttributeInfoEx
+    :members:
+    
+see also :class:`PyTango.AttributeInfo`
+
+.. autoclass:: PyTango.DeviceAttributeConfig
+    :members:
+
+Command
+~~~~~~~
+
+.. autoclass:: PyTango.DevCommandInfo
+   :members:
+
+.. autoclass:: PyTango.CommandInfo
+   :members:
+
+Other
+~~~~~
+
+.. autoclass:: PyTango.DeviceInfo
+    :members:
+
+.. autoclass:: PyTango.LockerInfo
+    :members:
+
+.. autoclass:: PyTango.PollDevice
+    :members:
+
+
+Storage classes
+---------------
+
+Attribute: DeviceAttribute
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. autoclass:: DeviceAttribute
+    :members:
+
+
+Command: DeviceData
+~~~~~~~~~~~~~~~~~~~
+
+Device data is the type used internally by Tango to deal with command parameters
+and return values. You don't usually need to deal with it, as command_inout
+will automatically convert the parameters from any other type and the result
+value to another type.
+
+You can still use them, using command_inout_raw to get the result in a DeviceData.
+
+You also may deal with it when reading command history.
+
+.. autoclass:: DeviceData
+    :members:
+
+
+Callback related classes
+------------------------
+
+If you subscribe a callback in a DeviceProxy, it will be run with a parameter.
+This parameter depends will be of one of the following classes depending on
+the callback type.
+
+.. autoclass:: PyTango.AttrReadEvent
+    :members:
+
+.. autoclass:: PyTango.AttrWrittenEvent
+    :members:
+
+.. autoclass:: PyTango.CmdDoneEvent
+    :members:
+
+
+Event related classes
+---------------------
+
+Event configuration information
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. autoclass:: PyTango.AttributeEventInfo
+    :members:
+
+.. autoclass:: PyTango.ArchiveEventInfo
+    :members:
+
+.. autoclass:: PyTango.ChangeEventInfo
+    :members:
+
+.. autoclass:: PyTango.PeriodicEventInfo
+    :members:
+
+Event arrived structures
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. autoclass:: PyTango.EventData
+    :members:
+
+.. autoclass:: PyTango.AttrConfEventData
+    :members:
+
+.. autoclass:: PyTango.DataReadyEventData
+    :members:
+
+
+History classes
+---------------
+
+.. autoclass:: PyTango.DeviceAttributeHistory
+    :show-inheritance:    
+    :members:
+
+See :class:`DeviceAttribute`.
+
+.. autoclass:: PyTango.DeviceDataHistory
+    :show-inheritance:
+    :members:
+
+See :class:`DeviceData`.
diff --git a/doc/client/other.rst b/doc/client/other.rst
new file mode 100644
index 0000000..910e026
--- /dev/null
+++ b/doc/client/other.rst
@@ -0,0 +1,60 @@
+.. currentmodule:: PyTango
+
+Enumerations & other classes
+----------------------------
+
+Enumerations
+~~~~~~~~~~~~
+
+.. autoclass:: PyTango.LockerLanguage
+
+.. autoclass:: PyTango.CmdArgType
+
+.. autoclass:: PyTango.MessBoxType
+
+.. autoclass:: PyTango.PollObjType
+
+.. autoclass:: PyTango.PollCmdCode
+
+.. autoclass:: PyTango..SerialModel
+
+.. autoclass:: PyTango.AttReqType
+
+.. autoclass:: PyTango.LockCmdCode
+
+.. autoclass:: PyTango.LogLevel
+
+.. autoclass:: PyTango.LogTarget
+
+.. autoclass:: PyTango.EventType
+
+.. autoclass:: PyTango.KeepAliveCmdCode
+
+.. autoclass:: PyTango.AccessControlType
+
+.. autoclass:: PyTango.asyn_req_type
+
+.. autoclass:: PyTango.cb_sub_model
+
+.. autoclass:: PyTango.AttrQuality
+
+.. autoclass:: PyTango.AttrWriteType
+
+.. autoclass:: PyTango.AttrDataFormat
+
+.. autoclass:: PyTango.DevSource
+
+.. autoclass:: PyTango.ErrSeverity
+
+.. autoclass:: PyTango.DevState
+
+.. autoclass:: PyTango.DispLevel
+
+Other classes
+~~~~~~~~~~~~~
+
+.. autoclass:: PyTango.Release
+    :members:
+    
+.. autoclass:: PyTango.TimeVal
+    :members:
\ No newline at end of file
diff --git a/doc/conf.py b/doc/conf.py
new file mode 100644
index 0000000..098d428
--- /dev/null
+++ b/doc/conf.py
@@ -0,0 +1,495 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+#
+# PyTango documentation build configuration file, created by
+# sphinx-quickstart on Fri Jun  5 14:31:50 2009.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+import re
+import PyTango
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+sys.path.append(os.path.abspath('sphinxext'))
+
+# -- General configuration -----------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.pngmath',
+              'sphinx.ext.autodoc',
+              'sphinx.ext.doctest',
+              'sphinx.ext.graphviz',
+              'ipython_console_highlighting',
+              'spock_console_highlighting']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'PyTango'
+copyright = u'2010, ALBA - CELLS'
+copyright = u"""Except where otherwise noted, content on this site is
+licensed under a Creative Commons Attribution 3.0 License"""
+
+#Ideally we would like to put the following html code for copyright... but how?
+'''<a rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/es/"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-sa/3.0/es/88x31.png" /></a><br /><span xmlns:dc="http://purl.org/dc/elements/1.1/" href="http://purl.org/dc/dcmitype/Text" property="dc:title" rel="dc:type">Tau Documentation</span> by <span xmlns:cc="http://creativecommons.org/ns#" property="cc:attributionName">CELLS - ALBA</span> is licensed under a <a rel="licens [...]
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '.'.join(PyTango.Release.version.split('.')[:2])
+# The full version, including alpha/beta/rc tags.
+release = PyTango.Release.version
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directory, that shouldn't be searched
+# for source files.
+exclude_trees = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+pygments_style = 'spock_console_highlighting.SpockStyle'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+html_theme = 'sphinxdoc'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+html_logo = 'logo.png'
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_use_modindex = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'PyTangodoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('index', 'PyTango.tex', u'PyTango Documentation',
+   u'PyTango team', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
+
+def copy_spaces(origin):
+    r = ''
+    for x in xrange(len(origin)):
+        if origin[x] in (' ', '\t'):
+            r += origin[x]
+        else:
+            return r
+    return r
+
+def type_to_link(tipus):
+        if tipus[:9] == 'sequence<' and tipus[-1:] == '>':
+            return 'sequence<' + type_to_link(tipus[9:-1]) + '>'
+        #elif tipus in dir(PyTango):
+        else:
+            return ':class:`' + tipus + "`"
+        #else:
+        #    return tipus
+
+def type_to_pytango_link(tipus):
+        if tipus[:9] == 'sequence<' and tipus[-1:] == '>':
+            return 'sequence<' + type_to_link(tipus[9:-1]) + '>'
+        elif tipus in dir(PyTango):
+            return ':class:`' + tipus + "`"
+        else:
+           return tipus
+
+def possible_type_to_link(text):
+    if len(text) and text[0] == '(' and text[-1] == ')':
+        return '(' + type_to_link(text[1:-1]) +')'
+    return text
+
+def parse_typed_line(line):
+    spacesSplit = line.strip().split(' ')
+    first = spacesSplit[0].strip()
+    return possible_type_to_link(first) + ' ' + ' '.join(spacesSplit[1:])
+
+def parse_parameters(line):
+    spaces = copy_spaces(line)
+    miniLine = line.strip()
+
+    if miniLine[:2] != '- ':
+        return line
+
+    spl = miniLine[2:].split(':', 1)
+
+    assert(len(spl) == 2)
+    
+    return spaces + ':' + spl[0].strip() + ': ' + parse_typed_line(spl[1])
+
+
+def parse_bullet_with_type(line):
+    spaces = copy_spaces(line)
+    miniLine = line.strip()
+
+    if miniLine[:2] not in ['- ', '* ']:
+        return line
+
+    spl = miniLine.split(':', 1)
+
+    if len(spl) != 2:
+        return line
+
+    return spaces + spl[0] + ': ' + parse_typed_line(spl[1])
+
+
+def parse_throws(line):
+    words = re.split('(\W+)', line)
+    assert(line == ''.join(words))
+    return ''.join(map(type_to_pytango_link, words))
+
+
+# http://codedump.tumblr.com/post/94712647/handling-python-docstring-indentation
+def docstring_to_lines(docstring):
+    if not docstring:
+        return []
+    lines = docstring.expandtabs().splitlines()
+
+    # Determine minimum indentation (first line doesn't count):
+    indent = sys.maxint
+    for line in lines[1:]:
+        stripped = line.lstrip()
+        if stripped:
+            indent = min(indent, len(line) - len(stripped))
+
+    # Remove indentation (first line is special):
+    trimmed = [lines[0].strip()]
+    if indent < sys.maxint:
+        for line in lines[1:]:
+            trimmed.append(line[indent:].rstrip())
+
+    # Strip off trailing and leading blank lines:
+    while trimmed and not trimmed[-1]:
+        trimmed.pop()
+    while trimmed and not trimmed[0]:
+        trimmed.pop(0)
+    return trimmed
+
+def search_ONLY_signature(name, text):
+    lines = docstring_to_lines(text)
+
+    # There should be ONE signature and must be the FIRST text
+    # Signature is the ONLY starting at position 0
+
+    signatureLine = None
+
+    for ln in xrange(len(lines)):
+        line = lines[ln]
+
+        if len(line.strip()) and line[0] != ' ':
+            parentesis = line.split('(', 1)
+            fname = parentesis[0].strip()
+            if len(parentesis)==2 and fname == name.rsplit('.',1)[1]:
+                if signatureLine is not None: # More than one signature!
+                    return None
+                signatureLine = ln
+            else:
+                return None # There's a text as FIRST text that's NOT the signature!
+
+    if signatureLine is None:
+        return None
+
+    return lines[signatureLine]
+
+def split_signature(text):
+    if text is None:
+        return None
+    
+    # split "fname(params)", "returntype"
+    ops = text.split('->')
+    if len(ops) != 2:
+        return None
+    
+    # get rid of "fname"
+    params = ops[0].strip()
+    ret_type = ops[1].strip()
+    p = params.find('(')
+    if p < 0:
+        return None
+    params = params[p:]
+    return params, ret_type
+    
+
+    
+_with_only_one_signature_methods = {}
+
+def __reformat_lines(app, what, name, obj, options, lines):
+    global _with_only_one_signature_methods
+    if what != 'method':
+        for ln in xrange(len(lines)):
+            lines[ln] = parse_bullet_with_type(lines[ln])
+        return
+
+    toinsert = []
+    parsingParameters = False
+    parsingThrows = False
+
+    toinsert.append((0, ""))
+    
+    for ln in xrange(len(lines)):
+        line = lines[ln]
+
+        if len(line) and line[0] != ' ':
+            if name in _with_only_one_signature_methods:
+                # This method has one and only one signature. So it will
+                # be displayed by sphinx, there's no need for us to fake
+                # it here...
+                lines[ln] = ""
+            else:
+                parentesis = line.split('(', 1)
+                fname = parentesis[0].strip()
+                if len(parentesis)==2 and fname == name.rsplit('.',1)[1]:
+                    sg = split_signature(line)
+                    if sg is not None:
+                        # Main lines are like small titles (**bold**):
+                        lines[ln] = '**' + fname +'** *' + sg[0] + '* **->** ' + type_to_link(sg[1])
+                        # Add an ENTER after the title, to make a different
+                        # paragraph. So if I have 2 signatures, there's no problem
+                        # with it...
+                        toinsert.append((ln+1, ""))
+
+                    ## Main lines are like small titles (**bold**):
+                    #lines[ln]='**' + line.strip() + '**'
+                    ## Add an ENTER after the title, to make a different
+                    ## paragraph. So if I have 2 signatures, there's no problem
+                    ## with it...
+                    #toinsert.append((ln+1, ""))
+
+
+        # Mark the "New in this version" lines...
+        if line.strip()[:14] == "New in PyTango":
+            lines[ln] = copy_spaces(lines[ln]) + "*" + line.strip() + "*"
+            parsingParameters = False
+            parsingThrows = False
+
+        # Look for special control_words
+        # To replace the actual syntax: "Return   : something"
+        # with the one understood by reStructuredText ":Return: something"
+        spl = line.strip().split(':', 1)
+        control_word = spl[0].strip()
+            
+        if ((len(spl) != 2)
+            or (control_word not in ["Parameters", "Return", "Throws", "Example", "See Also" ]) ):
+                if parsingParameters:
+                    lines[ln] = parse_parameters(line)
+                elif parsingThrows:
+                    lines[ln] = parse_throws(line)
+                continue
+
+        parsingParameters = False
+        parsingThrows = False
+        spaces = copy_spaces(line)
+
+        # The Example control word is even more special. I will put
+        # the contents from the following line into a code tag (::)
+        if control_word == 'Example':
+            lines[ln] = spaces + ":" + control_word + ": " + spl[1]
+            toinsert.append((ln+1, ""))
+            toinsert.append((ln+1, spaces + ' ::'))
+            toinsert.append((ln+1, ""))
+        elif control_word == 'Parameters':
+            lines[ln] = spaces + ":Parameters:" + parse_parameters(spl[1])
+            parsingParameters = True
+        elif control_word == 'Return':
+            lines[ln] = spaces + ":Return: " + parse_typed_line(spl[1])
+        elif control_word == "Throws":
+            lines[ln] = spaces + ":Throws:" + parse_throws(spl[1])
+            parsingThrows = True
+        else:
+            lines[ln] = spaces + ":" + control_word + ": " + spl[1]
+
+    for x in xrange(len(toinsert)-1, -1, -1):
+        pos, txt = toinsert[x]
+        lines.insert(pos, txt)
+
+
+def __process_signature(app, what, name, obj, options, signature, return_annotation):
+    global _with_only_one_signature_methods
+    if what != 'method':
+        return
+    sg = split_signature(search_ONLY_signature(name, obj.__doc__))
+    if sg is not None:
+        _with_only_one_signature_methods[name] = True
+        return sg
+    return (signature, return_annotation)
+
+def setup(app):
+    # sphinx will call these methods when he finds an object to document.
+    # I want to edit the docstring to adapt its format to something more
+    # beautiful.
+    # I also want to edit the signature because boost methods have no
+    # signature. I will read the signature from the docstring.
+    # The order sphinx will call it is __process_signature, __reformat_lines.
+    # And it is important because I keep some information between the two
+    # processes
+    # Problem is __process_signature works great with python methods...
+    # but is not even called for methods defined by boost. So, as it is,
+    # is useless now.
+    
+    #app.connect('autodoc-process-signature', __process_signature)
+    app.connect('autodoc-process-docstring', __reformat_lines)
diff --git a/doc/contents.rst b/doc/contents.rst
new file mode 100644
index 0000000..fe0a652
--- /dev/null
+++ b/doc/contents.rst
@@ -0,0 +1,21 @@
+
+.. currentmodule:: PyTango
+
+.. _contents: 
+
+========
+Contents
+========
+
+.. toctree::
+    :maxdepth: 2
+
+    start
+    spock/index
+    API <api>
+    faq
+    History of changes <revision>
+    
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
\ No newline at end of file
diff --git a/doc/database.rst b/doc/database.rst
new file mode 100644
index 0000000..0450b3c
--- /dev/null
+++ b/doc/database.rst
@@ -0,0 +1,29 @@
+The Tango Database Python API
+=============================
+
+.. currentmodule:: PyTango
+
+.. autoclass:: PyTango.Database
+    :members:
+
+.. autoclass:: PyTango.DbDatum
+    :members:
+
+.. autoclass:: PyTango.DbDevExportInfo
+    :members:
+
+.. autoclass:: PyTango.DbDevExportInfo
+    :members:
+
+.. autoclass:: PyTango.DbDevImportInfo
+    :members:
+
+.. autoclass:: PyTango.DbDevInfo
+    :members:
+
+.. autoclass:: PyTango.DbHistory
+    :members:
+
+.. autoclass:: PyTango.DbServerInfo
+    :members:
+
diff --git a/doc/exception.rst b/doc/exception.rst
new file mode 100644
index 0000000..817ae35
--- /dev/null
+++ b/doc/exception.rst
@@ -0,0 +1,317 @@
+.. currentmodule:: PyTango
+
+.. highlight:: python
+   :linenothreshold: 4
+
+Exception Handling
+==================
+
+Exception definition
+--------------------
+
+All the exceptions that can be thrown by the underlying Tango C++ API are available
+in the PyTango python module. Hence a user can catch one of the following
+exceptions:
+
+    - :class:`DevFailed`
+    - :class:`ConnectionFailed`
+    - :class:`CommunicationFailed`
+    - :class:`WrongNameSyntax`
+    - :class:`NonDbDevice`
+    - :class:`WrongData`
+    - :class:`NonSupportedFeature`
+    - :class:`AsynCall`
+    - :class:`AsynReplyNotArrived`
+    - :class:`EventSystemFailed`
+    - :class:`NamedDevFailedList`
+    - :class:`DeviceUnlocked`
+
+When an exception is caught, the sys.exc_info() function returns a tuple of three
+values that give information about the exception that is currently being handled.
+The values returned are (type, value, traceback).
+Since most functions don't need access to the traceback, the best solution is to
+use something like exctype, value = sys.exc_info()[:2] to extract only the exception
+type and value. If one of the Tango exceptions is caught, the exctype will be class
+name of the exception (DevFailed, .. etc) and the value a tuple of dictionary objects
+all of which containing the following kind of key-value pairs:
+
+- **reason**: a string describing the error type (more readable than the associated error code)
+- **desc**: a string describing in plain text the reason of the error.
+- **origin**: a string giving the name of the (C++ API) method which thrown the exception
+- **severity**: one of the strings WARN, ERR, PANIC giving severity level of the error.
+
+::
+
+    #  Protect the script from Exceptions raised by the Tango or python itself
+    try:
+        # Get proxy on the tangotest1 device
+        print "Getting DeviceProxy "
+        tangotest = DeviceProxy("tango/tangotest/1")
+
+    #Catch Tango and Systems  Exceptions
+    except DevFailed:
+        exctype , value = sys.exc_info()[:2]
+        print "Failed with exception ! " , exctype
+        for err in value:
+            print " reason" , err.reason
+            print " description" , err.desc
+            print " origin" , err.origin
+            print " severity" , err.severity
+
+Throwing exception in a device server
+-------------------------------------
+
+The C++ Tango::Except class with its most important methods have been wrapped to Python.
+Therefore, in a Python device server, you have the following methods to throw, re-throw or
+print a Tango::DevFailed exception :
+
+- *throw_exception()* which is a static method
+- *re_throw_exception()* which is also a static method
+- *print_exception()* which is also a static method
+
+The following code is an example of a command method requesting a command on a sub-device and re-throwing
+the exception in case of::
+
+    try:
+        dev.command_inout("SubDevCommand")
+    except PyTango.DevFailed, e:
+        PyTango.Except.re_throw_exception(e,
+            "MyClass_CommandFailed",
+            "Sub device command SubdevCommand failed",
+            "Command()")
+
+:line 2: Send the command to the sub device in a try/catch block
+:line 4-6: Re-throw the exception and add a new level of information in the exception stack
+
+
+Exception API
+-------------
+
+.. autoclass:: PyTango.Except
+   :show-inheritance:
+   :members:
+    
+    .. staticmethod:: print_exception(exception)
+        
+        Prints the Tango exception on the standard output
+
+        :param exception: tango exception
+        :type exception: :class:`DevFailed`
+        :rtype: None
+
+
+.. autoclass:: PyTango.DevError
+   :show-inheritance:
+   :members:
+
+.. autoexception:: PyTango.DevFailed
+   :show-inheritance:
+   :members:
+
+.. autoexception:: PyTango.ConnectionFailed
+   :show-inheritance:
+    
+    This exception is thrown when a problem occurs during the connection 
+    establishment between the application and the device. The API is stateless. 
+    This means that DeviceProxy constructors filter most of the exception 
+    except for cases described in the following table. 
+    
+    The desc DevError structure field allows a user to get more precise information. These informations are :
+    
+    **DB_DeviceNotDefined**
+        The name of the device not defined in the database 
+    **API_CommandFailed** 
+        The device and command name 
+    **API_CantConnectToDevice** 
+        The device name 
+    **API_CorbaException** 
+        The name of the CORBA exception, its reason, its locality, its completed 
+        flag and its minor code 
+    **API_CantConnectToDatabase** 
+        The database server host and its port number 
+    **API_DeviceNotExported** 
+        The device name
+
+
+.. autoexception:: PyTango.CommunicationFailed
+   :show-inheritance:
+    
+    This exception is thrown when a communication problem is detected during 
+    the communication between the client application and the device server. It 
+    is a two levels Tango::DevError structure. In case of time-out, the DevError
+    structures fields are: 
+
+    +-------+--------------------+-------------------------------------------------+----------+
+    | Level |      Reason        |                   Desc                          | Severity |
+    +=======+====================+=================================================+==========+
+    |   0   | API_CorbaException | CORBA exception fields translated into a string |   ERR    |
+    +-------+--------------------+-------------------------------------------------+----------+
+    |   1   | API_DeviceTimedOut | String with time-out value and device name      |   ERR    |
+    +-------+--------------------+-------------------------------------------------+----------+
+
+    For all other communication errors, the DevError structures fields are: 
+
+    +-------+-------------------------+----------------------------------------------------+----------+
+    | Level |         Reason          |                     Desc                           | Severity |
+    +=======+=========================+====================================================+==========+
+    |   0   | API_CorbaException      |   CORBA exception fields translated into a string  |   ERR    |
+    +-------+-------------------------+----------------------------------------------------+----------+
+    |   1   | API_CommunicationFailed | String with device, method, command/attribute name |   ERR    |
+    +-------+-------------------------+----------------------------------------------------+----------+
+
+
+.. autoexception:: PyTango.WrongNameSyntax
+   :show-inheritance:
+
+This exception has only one level of Tango::DevError structure. The possible 
+value for the reason field are :
+
+    **API_UnsupportedProtocol**
+        This error occurs when trying to build a DeviceProxy or an AttributeProxy 
+        instance for a device with an unsupported protocol. Refer to the appendix 
+        on device naming syntax to get the list of supported database modifier 
+    **API_UnsupportedDBaseModifier**
+        This error occurs when trying to build a DeviceProxy or an AttributeProxy 
+        instance for a device/attribute with a database modifier unsupported. 
+        Refer to the appendix on device naming syntax to get the list of 
+        supported database modifier 
+    **API_WrongDeviceNameSyntax**
+        This error occurs for all the other error in device name syntax. It is 
+        thrown by the DeviceProxy class constructor. 
+    **API_WrongAttributeNameSyntax**
+        This error occurs for all the other error in attribute name syntax. It 
+        is thrown by the AttributeProxy class constructor. 
+    **API_WrongWildcardUsage**
+        This error occurs if there is a bad usage of the wildcard character 
+
+.. autoexception:: PyTango.NonDbDevice
+   :show-inheritance:
+
+    This exception has only one level of Tango::DevError structure. The reason 
+    field is set to API_NonDatabaseDevice. This exception is thrown by the API 
+    when using the DeviceProxy or AttributeProxy class database access for 
+    non-database device. 
+
+.. autoexception:: PyTango.WrongData
+   :show-inheritance:
+
+    This exception has only one level of Tango::DevError structure. 
+    The possible value for the reason field are :
+
+    **API_EmptyDbDatum**
+        This error occurs when trying to extract data from an empty DbDatum 
+        object 
+    **API_IncompatibleArgumentType**
+        This error occurs when trying to extract data with a type different 
+        than the type used to send the data 
+    **API_EmptyDeviceAttribute**
+        This error occurs when trying to extract data from an empty 
+        DeviceAttribute object 
+    **API_IncompatibleAttrArgumentType**
+        This error occurs when trying to extract attribute data with a type 
+        different than the type used to send the data 
+    **API_EmptyDeviceData**
+        This error occurs when trying to extract data from an empty DeviceData 
+        object 
+    **API_IncompatibleCmdArgumentType**
+        This error occurs when trying to extract command data with a type 
+        different than the type used to send the data 
+
+.. autoexception:: PyTango.NonSupportedFeature
+   :show-inheritance:
+
+    This exception is thrown by the API layer when a request to a feature 
+    implemented in Tango device interface release n is requested for a device 
+    implementing Tango device interface n-x. There is one possible value for 
+    the reason field which is API_UnsupportedFeature. 
+
+.. autoexception:: PyTango.AsynCall
+   :show-inheritance:
+
+    This exception is thrown by the API layer when a the asynchronous model id
+    badly used. This exception has only one level of Tango::DevError structure. 
+    The possible value for the reason field are :
+
+    **API_BadAsynPollId**
+        This error occurs when using an asynchronous request identifier which is not 
+        valid any more. 
+    **API_BadAsyn**
+        This error occurs when trying to fire callback when no callback has been 
+        previously registered 
+    **API_BadAsynReqType**
+        This error occurs when trying to get result of an asynchronous request with 
+        an asynchronous request identifier returned by a non-coherent asynchronous 
+        request (For instance, using the asynchronous request identifier returned 
+        by a command_inout_asynch() method with a read_attribute_reply() attribute). 
+
+.. autoexception:: PyTango.AsynReplyNotArrived
+   :show-inheritance:
+
+    This exception is thrown by the API layer when:
+
+        - a request to get asynchronous reply is made and the reply is not yet arrived
+        - a blocking wait with timeout for asynchronous reply is made and the timeout expired.
+
+    There is one possible value for the reason field which is API_AsynReplyNotArrived. 
+
+.. autoexception:: PyTango.EventSystemFailed
+   :show-inheritance:
+
+    This exception is thrown by the API layer when subscribing or unsubscribing 
+    from an event failed. This exception has only one level of Tango::DevError 
+    structure. The possible value for the reason field are :
+
+    **API_NotificationServiceFailed**
+        This error occurs when the subscribe_event() method failed trying to 
+        access the CORBA notification service 
+    **API_EventNotFound**
+        This error occurs when you are using an incorrect event_id in the 
+        unsubscribe_event() method 
+    **API_InvalidArgs**
+        This error occurs when NULL pointers are passed to the subscribe or 
+        unsubscribe event methods 
+    **API_MethodArgument**
+        This error occurs when trying to subscribe to an event which has already 
+        been subsribed to 
+    **API_DSFailedRegisteringEvent**
+        This error means that the device server to which the device belongs to 
+        failed when it tries to register the event. Most likely, it means that 
+        there is no event property defined 
+    **API_EventNotFound**
+        Occurs when using a wrong event identifier in the unsubscribe_event 
+        method 
+
+
+.. autoexception:: PyTango.DeviceUnlocked
+   :show-inheritance:
+
+    This exception is thrown by the API layer when a device locked by the 
+    process has been unlocked by an admin client. This exception has two levels 
+    of Tango::DevError structure. There is only possible value for the reason 
+    field which is
+
+    **API_DeviceUnlocked**
+        The device has been unlocked by another client (administration client) 
+
+    The first level is the message reported by the Tango kernel from the server 
+    side. The second layer is added by the client API layer with informations on
+    which API call generates the exception and device name. 
+
+.. autoexception:: PyTango.NotAllowed
+   :show-inheritance:
+
+
+.. autoexception:: PyTango.NamedDevFailedList
+   :show-inheritance:
+
+    This exception is only thrown by the DeviceProxy::write_attributes() 
+    method. In this case, it is necessary to have a new class of exception 
+    to transfer the error stack for several attribute(s) which failed during 
+    the writing. Therefore, this exception class contains for each attributes
+    which failed :
+
+        - The name of the attribute
+        - Its index in the vector passed as argumen tof the write_attributes() method
+        - The error stack
+
+
diff --git a/doc/faq.rst b/doc/faq.rst
new file mode 100644
index 0000000..aec878b
--- /dev/null
+++ b/doc/faq.rst
@@ -0,0 +1,364 @@
+.. currentmodule:: PyTango
+
+FAQ
+===
+
+Answers to general Tango questions can be found at http://www.tango-controls.org/tutorials
+
+Please also check http://www.tango-controls.org/howtos for a list of Tango howtos
+
+Where are the usual bjam files?
+-------------------------------
+
+Starting from PyTango 7.0.0 the prefered way to build PyTango is using the standard
+python distutils package. This means that:
+
+- you do NOT have to install the additional bjam package
+- you do NOT have to change 3 configuration files
+- you do NOT need to have 2Gb of RAM to compile PyTango.
+
+Please check the compilation chapter for details on how to build PyTango.
+
+I got a libbost_python error when I try to import PyTango module
+----------------------------------------------------------------
+
+doing:
+    >>> import PyTango
+    ImportError: libboost_python-gcc43-mt-1_38.so.1.38.0: cannot open shared object file: No such file or directory
+
+You must check that you have the correct boost python installed on your computer.
+To see which boost python file PyTango needs type::
+
+    $ ldd /usr/lib/python2.5/site-packages/PyTango/_PyTango.so
+    linux-vdso.so.1 =>  (0x00007fff48bfe000)
+    libtango.so.7 => /home/homer/local/lib/libtango.so.7 (0x00007f393fabb000)
+    liblog4tango.so.4 => /home/homer/local/lib/liblog4tango.so.4 (0x00007f393f8a0000)
+    **libboost_python-gcc43-mt-1_38.so.1.38.0 => not found**
+    libpthread.so.0 => /lib/libpthread.so.0 (0x00007f393f65e000)
+    librt.so.1 => /lib/librt.so.1 (0x00007f393f455000)
+    libdl.so.2 => /lib/libdl.so.2 (0x00007f393f251000)
+    libomniORB4.so.1 => /usr/local/lib/libomniORB4.so.1 (0x00007f393ee99000)
+    libomniDynamic4.so.1 => /usr/local/lib/libomniDynamic4.so.1 (0x00007f393e997000)
+    libomnithread.so.3 => /usr/local/lib/libomnithread.so.3 (0x00007f393e790000)
+    libCOS4.so.1 => /usr/local/lib/libCOS4.so.1 (0x00007f393e359000)
+    libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00007f393e140000)
+    libc.so.6 => /lib/libc.so.6 (0x00007f393ddce000)
+    libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f393dac1000)
+    libm.so.6 => /lib/libm.so.6 (0x00007f393d83b000)
+    /lib64/ld-linux-x86-64.so.2 (0x00007f3940a4c000)
+
+
+My python code uses PyTango 3.0.4 API. How do I change to 7.0.0 API?
+--------------------------------------------------------------------
+
+To ease migration effort, PyTango 7 provides an alternative module called
+PyTango3.
+
+Changing your python import from::
+
+    import PyTango
+    
+to::
+
+    import PyTango3 as PyTango
+    
+should allow you to execute your old PyTango code using the new PyTango 7 library.
+
+Please note that you should as soon as possible migrate the code to Tango 7
+since the PyTango team cannot assure the maintainability of the PyTango3 module.
+
+Please find below a basic set of rules to migrate from PyTango 3.0.x to 7:
+
+General rule of thumb for data types
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The first important thing to be aware of when migrating from PyTango <= 3.0.4 to
+PyTango >= 7 is that the data type mapping from tango to python and vice versa is
+not always the same. The following table summarizes the differences:
+
++-------------------------+-------------------------------------------+-------------------------------------------+
+|   Tango data type       |              PyTango 7 type               | PyTango <= 3.0.4 type                     |
++=========================+===========================================+===========================================+
+|          DEV_VOID       |                    No data                |                    No data                |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|       DEV_BOOLEAN       | bool                                      | bool                                      |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|         DEV_SHORT       | int                                       | int                                       |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|         DEV_LONG        | int                                       | int                                       |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|        DEV_LONG64       | long (on a 32 bits computer) or           | long (on a 32 bits computer) or           |
+|                         | int (on a 64 bits computer)               | int (on a 64 bits computer)               |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|         DEV_FLOAT       | float                                     | float                                     |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|       DEV_DOUBLE        | float                                     | float                                     |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|        DEV_USHORT       | int                                       | int                                       |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|        DEV_ULONG        | int                                       | int                                       |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|        DEV_ULONG64      | long (on a 32 bits computer) or           | long (on a 32 bits computer) or           |
+|                         | int (on a 64 bits computer)               | int (on a 64 bits computer)               |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|        DEV_STRING       | str                                       | str                                       |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|    DEVVAR_CHARARRAY     | sequence<int>                             | list<int>                                 |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|    DEVVAR_SHORTARRAY    | sequence<int>                             | list<int>                                 |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|    DEVVAR_LONGARRAY     | sequence<int>                             | list<int>                                 |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|   DEVVAR_LONG64ARRAY    | sequence<long> (on a 32 bits computer) or | list<long> (on a 32 bits computer) or     |
+|                         | sequence<int> (on a 64 bits computer)     | list<int> (on a 64 bits computer)         |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|    DEVVAR_FLOATARRAY    | sequence<float>                           | list<float>                               |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|   DEVVAR_DOUBLEARRAY    | sequence<float>                           | list<float>                               |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|   DEVVAR_USHORTARRAY    | sequence<int>                             | list<int>                                 |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|   DEVVAR_ULONGARRAY     | sequence<int>                             | list<int>                                 |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|  DEVVAR_ULONG64ARRAY    | sequence<long> (on a 32 bits computer) or | list<long> (on a 32 bits computer) or     |
+|                         | sequence<int> (on a 64 bits computer)     | list<int> (on a 64 bits computer)         |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|   DEVVAR_STRINGARRAY    | sequence<str>                             | list<str>                                 |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|                         | A sequence with two elements:             | A list with two elements:                 |
+| DEVVAR_LONGSTRINGARRAY  | 1. sequence<int>                          |  1. list<int>                             |
+|                         | 2. sequence<str>                          |  2. list<str>                             |
++-------------------------+-------------------------------------------+-------------------------------------------+
+|                         | A sequence with two elements:             | A list with two elements:                 |
+|DEVVAR_DOUBLESTRINGARRAY | 1. sequence<float>                        |  1. list<float>                           |
+|                         | 2. sequence<str>                          |  2. list<str>                             |
++-------------------------+-------------------------------------------+-------------------------------------------+
+
+Note that starting from PyTango 7 you **cannot assume anything** about the concrete 
+sequence implementation for the tango array types in PyTango.
+This means that the following code (valid in PyTango <= 3.0.4)::
+
+    import PyTango
+    dp = PyTango.DeviceProxy("my/device/experiment")
+    da = dp.read_attribute("array_attr")
+    if isinstance(da.value, list):
+        print "array_attr is NOT a scalar attribute"
+
+must be replaced with::
+
+    import operator, types
+    import PyTango
+    dp = PyTango.DeviceProxy("my/device/experiment")
+    da = dp.read_attribute("array_attr")
+    if operator.isSequence(da.value) and not type(da.value) in types.StringTypes:
+        print "array_attr is NOT a scalar attribute"
+
+Note that the above example is intended for demonstration purposes only. For 
+reference, the proper code would be::
+
+    import PyTango
+    dp = PyTango.DeviceProxy("my/device/experiment")
+    da = dp.read_attribute("array_attr")
+    if not da.data_format is PyTango.AttrDataFormat.SCALAR:
+        print "array_attr is NOT a scalar attribute"
+    
+Server
+~~~~~~
+
+#. replace `PyTango.PyUtil` with :class:`Util`
+
+#. replace `PyTango.PyDeviceClass` with :class:`DeviceClass`
+
+#. state and status overwrite
+    in PyTango <= 3.0.4, in order to overwrite the default state and status in a device
+    server, you had to reimplement **State()** and **Status()** methods respectively.
+
+    in PyTango 7 the methods have been renamed to **dev_state()** and **dev_status()** in
+    order to match the C++ API.
+
+General
+~~~~~~~
+
+#. AttributeValue does **NOT** exist anymore.
+    - the result of a read_attribute call on a :class:`DeviceProxy` / :class:`Group`
+      is now a :class:`DeviceAttribute` object
+    - write_attribute does not accept AttributeValue anymore
+    
+    (See :class:`DeviceProxy` API documentation for more details)
+    
+#. command_inout for commands with parameter type DevVar****StringArray don't accept items in second sequence not being strings:
+    For example, a tango command 'DevVoid Go(DevVarDoubleArray)' in tango 3.0.4
+    could be executed by calling::
+        
+        dev_proxy.command_inout( 'Go', [[1.0, 2.0], [1, 2, 3]] )
+    
+    and the second list would internally be converted to ['1', '2', '3'].
+    Starting from PyTango 7 this is not allowed anymore. So the above code 
+    must be changed to::
+    
+        dev_proxy.command_inout( 'Go', [[1.0, 2.0], ['1', '2', '3']] )
+
+#. :class:`EventType` enumeration constants changed to match C++ enumeration
+    - CHANGE -> CHANGE_EVENT
+    - QUALITY -> QUALITY_EVENT
+    - PERIODIC -> PERIODIC_EVENT
+    - ARCHIVE -> ARCHIVE_EVENT
+    - USER -> USER_EVENT
+    - ATTR_CONF_EVENT remains
+
+#. Exception handling
+    in 3.0.4 :class:`DevFailed` was a tuple of dictionaries. 
+    Now :class:`DevFailed` is a tuple of :class:`DevError`.
+    This means that code::
+
+        try:
+            tango_fail()
+        except PyTango.DevFailed as e:
+            print e.args[0]['reason']
+
+    needs to be replaced with::
+
+        try:
+            tango_fail()
+        except PyTango.DevFailed as e:
+            print e.args[0].reason
+
+
+Optional
+~~~~~~~~
+
+The following is a list of API improvements. Some where added for performance 
+reasons, others to allow for a more pythonic interface, others still to reflect 
+more adequately the C++ interface. They are not mandatory since the original 
+interface will still be available.
+
+Server side V3 to V4 upgrade
+############################
+
+If you want your server to support the V4 interface provided by Tango 7
+instead of the V3 provided by Tango 6:
+
+- replace the inheritance of your device class from :class:`Device_3Impl` to :class:`Device_4Impl`
+- in the `init_device` method replace the call::
+     
+     Device_3Impl.init_device(self)
+
+  with::
+  
+     Device_4Impl.init_device(self)
+
+  or better yet, if your device class only inherits from :class:`Device_4Impl`::
+  
+     super(<your class>, self).init_device()
+
+Improved server side image attribute read API
+#############################################
+
+In PyTango <= 3.0.4, to set the value of an image attribute you needed it
+as a flat list. Consider you want to set as value the following image::
+
+    # Image:
+    #  | 1  2 |
+    #  | 3  4 |
+    
+In order to tell tango the dimensions of the image you had to specify them as::
+
+    image = [ 1, 2, 3, 4]
+    dim_x = 2
+    dim_y = 2
+    attr.set_value(image, dim_x, dim_y)
+
+In PyTango7 it is still supported, but the preferred way is to use a
+sequence of sequences (instead of a flat sequence), so the dimensions
+are inherent and not needed anymore::
+
+    image = [ [1, 2], [3, 4]]
+    attr.set_value(image)
+
+If you use a numpy array as the sequence of sequences you can get better
+performance::
+
+    image = numpy.array([ [1, 2], [3, 4]], dtype=numpy.int32)
+    attr.set_value(image)
+
+Likewise, calls to::
+
+    PyTango.set_attribute_value_date_quality(attr, value, date, quality, dim_x, dim_y)
+
+can be replaced with::
+
+    attr.set_value_date_quality(value, date, quality)
+
+Improved server side attribute write API
+########################################
+
+Imagine the following value is written to our IMAGE attribute::
+
+    # Image:
+    #  | 1  2 |
+    #  | 3  4 |
+
+This is what you would do with PyTango <= 3.0.4::
+
+    flatList = []
+    attr.get_write_value(flatList)
+    print "flatList =", flatList
+    # flatList = [ 1, 2, 3, 4 ]
+
+You can still do it with PyTango7. However I recommend::
+
+    image = attr.get_write_value()
+    print "image =", image
+    # image = numpy.array([[1, 2], [3, 4]])
+
+If PyTango7 is compiled without numpy support, you will get a sequence
+of sequences, which makes more sense than a flat list.
+
+If PyTango7 is compiled with numpy support it does not only makes more sense
+but it is also considerably **faster and memory friendlier**.
+
+If PyTango is compiled with numpy support but you prefer a list of lists for
+some attribute, you can do::
+
+    image = attr.get_write_value(PyTango.ExtractAs.List)
+    print "image =", image
+    # image = [[1, 2], [3, 4]]
+
+Also the SCALAR attribute case is much **cleaner** now. Instead of::
+
+    data = []
+    attr.get_write_value(data)
+    actualData = data[0]
+
+You can just write::
+
+    actualData = attr.get_write_value()
+
+Why is there a "-Wstrict-prototypes" warning when I compile PyTango?
+--------------------------------------------------------------------
+
+The PyTango prefered build system (distutils) uses the same flags used to compile
+Python to compile PyTango. It happens that Python is compiled as a pure C library
+while PyTango is a C++ library. Unfortunately one of the flags used by Python is
+the "-Wstrict-prototypes" which makes sence in a C compilation but not in a C++ 
+compilation.
+For reference here is the complete error message you may have:
+    
+    `cc1plus: warning: command line option "-Wstrict-prototypes" is valid for Ada/C/ObjC but not for C++`
+
+Do not worry about this warning since the compiler is ignoring the presence of this flag
+in the compilation.
+
+Why are there so many warnings when generating the documentation?
+-----------------------------------------------------------------
+PyTango uses boost python for the binding between C++ and Python and sphinx for
+document generation.
+When sphinx generates the PyTango API documentation it uses introspection to search
+for documentation in the python code. It happens that boost overrides some python
+introspection API for functions and methods which sphinx expects to have. Therefore
+you should see many warnings of type:
+
+    `(WARNING/2) error while formatting signature for PyTango.Device_4Impl.always_executed_hook: **arg is not a Python function**`
+
+Do not worry since sphinx is able to generate the proper documentation.
+
diff --git a/doc/index.rst b/doc/index.rst
new file mode 100644
index 0000000..0bb9bc8
--- /dev/null
+++ b/doc/index.rst
@@ -0,0 +1,61 @@
+.. PyTango documentation master file, created by
+    sphinx-quickstart on Fri Jun  5 14:31:50 2009.
+    You can adapt this file completely to your liking, but it should at least
+    contain the root `toctree` directive.
+
+.. highlight:: python
+   :linenothreshold: 4
+
+Welcome to PyTango 7.1 documentation!
+=====================================
+
+|PyTangoLogoMedium| |spocklogo|
+
+.. sidebar:: Latest news
+
+    2010-11-05:
+        PyTango 7.1.3 is out!
+
+    2010-08-19:
+        :ref:`Tango logging <logging>` updated
+
+    2010-08-06:
+        PyTango 7.1.2 is out!
+
+    2010-08-02:
+          Checkout the new PyTango companion: 
+          :ref:`spock` (an IPython_ based tango CLI)
+
+PyTango is a python module that exposes to Python_ the complete Tango_ C++ API.
+This includes both client and server API.
+
+This means that you can write not only tango applications (scripts, CLIs, GUIs) 
+that access tango device servers but also tango device servers themselves, all 
+of this in pure Python_.
+
+Check out the :ref:`getting started guide<getting-started>` to learn how to
+build and/or install PyTango and after that the :ref:`quick tour <quick-tour>` 
+can help you with the first steps in the PyTango world.
+
+If you need help understanding what Tango itself really is, you can check the
+Tango_ homepage where you will find plenty of documentation, faq and tutorials.
+
+.. toctree::
+    :hidden:
+
+    contents
+
+    
+:Last Update: |today|
+
+.. |PyTangoLogoMedium| image:: logo-medium.png
+    :align: middle
+    :alt: PyTango logo
+    
+.. |spocklogo| image:: spock/spock03.png
+    :align: middle
+    :alt: Spock console
+
+.. _Python: http://www.python.org/
+.. _IPython: http://ipython.scipy.org/
+.. _Tango: http://www.tango-controls.org/
\ No newline at end of file
diff --git a/doc/logo-medium.png b/doc/logo-medium.png
new file mode 100644
index 0000000..7bc4cc0
Binary files /dev/null and b/doc/logo-medium.png differ
diff --git a/doc/logo.png b/doc/logo.png
new file mode 100644
index 0000000..06b4527
Binary files /dev/null and b/doc/logo.png differ
diff --git a/doc/quicktour.rst b/doc/quicktour.rst
new file mode 100644
index 0000000..ab8c6cf
--- /dev/null
+++ b/doc/quicktour.rst
@@ -0,0 +1,531 @@
+.. _quick-tour:
+
+A quick tour
+------------
+
+This quick tour will guide you through the first steps on using PyTango.
+This is the new quick tour guide based on the :ref:`spock` console.
+You can still find the old version of this tour based on a simple python
+console :ref:`here <quick-tour-old>`.
+
+Check PyTango version
+~~~~~~~~~~~~~~~~~~~~~
+
+Start an ipython spock console with::
+
+    ipython -p spock
+
+and type:
+
+    .. sourcecode:: spock
+
+        Spock <homer:10000> [1]: PyTango.__version__
+                     Result [1]: '7.1.2'
+
+        Spock <homer:10000> [2]: PyTango.__version_long__
+                     Result [2]: '7.1.2dev0'
+
+        Spock <homer:10000> [3]: PyTango.__version_number__
+                     Result [3]: 712
+
+        Spock <homer:10000> [4]: PyTango.__version_description__
+                     Result [4]: 'This version implements the C++ Tango 7.1 API.'
+
+or alternatively:
+
+    .. sourcecode:: spock
+
+        Spock <homer:10000> [1]: PyTango.Release.version
+                     Result [1]: '7.1.2'
+
+        Spock <homer:10000> [2]: PyTango.Release.version_long
+                     Result [2]: '7.1.2dev0'
+
+        Spock <homer:10000> [3]: PyTango.Release.version_number
+                     Result [3]: 712
+
+        Spock <homer:10000> [4]: PyTango.Release.version_description
+                     Result [4]: 'This version implements the C++ Tango 7.1 API.'
+
+.. tip::
+
+    When typing, try pressing <tab>. Since Spock has autocomplete embedded you
+    should get a list of possible completions. Example::
+    
+        PyTango.Release.<tab>
+        
+    Should get a list of all members of :class:`PyTango.Release` class.
+
+Check Tango C++ version
+~~~~~~~~~~~~~~~~~~~~~~~
+
+From a client (This is only possible since PyTango 7.0.0)
+
+    .. sourcecode:: spock
+
+        Spock <homer:10000> [1]: import PyTango.constants
+
+        Spock <homer:10000> [2]: PyTango.constants.TgLibVers
+                     Result [2]: '7.1.1'
+
+From a server you can alternatively do::
+    
+    u = PyTango.Util.instance()
+    tg_cpp_lib_ver = u.get_tango_lib_release()
+    
+
+Test the connection to the Device and get it's current state
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+One of the most basic examples is to get a reference to a device and
+determine if it is running or not.
+
+    .. sourcecode:: spock
+        
+        Spock <homer:10000> [1]: # What is a DeviceProxy, really?
+        Spock <homer:10000> [1]: DeviceProxy?
+        DeviceProxy is the high level Tango object which provides the client with
+        an easy-to-use interface to TANGO devices. DeviceProxy provides interfaces
+        to all TANGO Device interfaces.The DeviceProxy manages timeouts, stateless
+        connections and reconnection if the device server is restarted. To create
+        a DeviceProxy, a Tango Device name must be set in the object constructor.
+
+        Example :
+           dev = PyTango.DeviceProxy("sys/tg_test/1")
+           
+        Spock <homer:10000> [2]: tangotest = DeviceProxy("sys/tg_test/1")
+
+        Spock <homer:10000> [3]: # ping it
+        Spock <homer:10000> [4]: tangotest.ping()
+                     Result [4]: 110
+
+        Spock <homer:10000> [3]: # Lets test the state
+        Spock <homer:10000> [5]: tangotest.state()
+                     Result [5]: PyTango._PyTango.DevState.RUNNING
+
+        Spock <homer:10000> [3]: # And now the status
+        Spock <homer:10000> [5]: tangotest.status()
+                     Result [5]: 'The device is in RUNNING state.'
+
+.. note::
+    Did you notice that you didn't write PyTango.DeviceProxy but instead just DeviceProxy?
+    This is because :ref:`spock` automatically exports the :class:`PyTango.DeviceProxy`,
+    :class:`PyTango.AttributeProxy`, :class:`PyTango.Database` and :class:`PyTango.Group`
+    classes to the namespace. If you are writting code outside :ref:`spock` you **MUST**
+    use the `PyTango` module prefix.
+
+.. tip::
+
+    When typing the device name in the :class:`PyTango.DeviceProxy` creation
+    line, try pressing the <tab> key. You should get a list of devices::
+    
+        tangotest = DeviceProxy("sys<tab>
+        
+    Better yet (and since the Tango Class of 'sys/tg_test/1' is 'TangoTest'),
+    try doing::
+    
+        tangotest = TangoTest("<tab>
+
+    Now the list of devices should be reduced to the ones that belong to the 
+    'TangoTest' class. Note that TangoTest only works in Spock. If you are 
+    writting code outside :ref:`spock` you **MUST** use 
+    :class:`PyTango.DeviceProxy` instead.
+    
+Execute commands with scalar arguments on a Device
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+As you can see in the following example, when scalar types are used, PyTango
+automatically manages the data types, and writing scripts is quite easy.
+
+    .. sourcecode:: spock
+    
+        Spock <homer:10000> [1]: tangotest = TangoTest("sys/tg_test/1")
+
+        Spock <homer:10000> [2]: # classical way
+        Spock <homer:10000> [2]: r = tangotest.command_inout("DevString", "Hello, world!")
+
+        Spock <homer:10000> [3]: print "Result of execution of DevString command =", r
+        Result of execution of DevString command = Hello, world!
+
+        Spock <homer:10000> [4]: # 'pythonic' way
+        Spock <homer:10000> [5]: tangotest.DevString("Hello, world!")
+                     Result [5]: 'Hello, world!'
+        
+        Spock <homer:10000> [6]: # type is automatically managed by PyTango
+        Spock <homer:10000> [7]: tangotest.DevULong(12456)
+                     Result [7]: 12456
+
+Execute commands with more complex types
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In this case you have to use put your arguments data in the correct python
+structures.
+
+    .. sourcecode:: spock
+    
+        Spock <homer:10000> [1]: tangotest = TangoTest("sys/tg_test/1")
+
+        Spock <homer:10000> [2]: argin = [1, 2, 3], ["Hello", "World"]
+
+        Spock <homer:10000> [3]: tango_test.DevVarLongArray(argin)
+                     Result [3]: [array([1, 2, 3]), ['Hello', 'World']]
+        
+.. note::
+    notice that the command returns a list of two elements. The first element is
+    a :class:`numpy.ndarray` (assuming PyTango is compiled with numpy support).
+    This is because PyTango does a best effort to convert all numeric array types
+    to numpy arrays.
+    
+Reading and writing attributes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Basic read/write attribute operations.
+
+    .. sourcecode:: spock
+    
+        Spock <homer:10000> [1]: # Read a scalar attribute
+        Spock <homer:10000> [2]: print tangotest.read_attribute("long_scalar")
+        DeviceAttribute[
+        data_format = PyTango._PyTango.AttrDataFormat.SCALAR
+              dim_x = 1
+              dim_y = 0
+         has_failed = False
+           is_empty = False
+               name = 'long_scalar'
+            nb_read = 1
+         nb_written = 1
+            quality = PyTango._PyTango.AttrQuality.ATTR_VALID
+        r_dimension = AttributeDimension(dim_x = 1, dim_y = 0)
+               time = TimeVal(tv_nsec = 0, tv_sec = 1281084943, tv_usec = 461730)
+               type = PyTango._PyTango.CmdArgType.DevLong
+              value = 239
+            w_dim_x = 1
+            w_dim_y = 0
+        w_dimension = AttributeDimension(dim_x = 1, dim_y = 0)
+            w_value = 0]
+            
+        Spock <homer:10000> [3]: # Read a spectrum attribute
+        Spock <pc151:10000> [4]: print tangotest.read_attribute("double_spectrum")
+        DeviceAttribute[
+        data_format = PyTango._PyTango.AttrDataFormat.SPECTRUM
+              dim_x = 20
+              dim_y = 0
+         has_failed = False
+           is_empty = False
+               name = 'double_spectrum'
+            nb_read = 20
+         nb_written = 20
+            quality = PyTango._PyTango.AttrQuality.ATTR_VALID
+        r_dimension = AttributeDimension(dim_x = 20, dim_y = 0)
+               time = TimeVal(tv_nsec = 0, tv_sec = 1281085195, tv_usec = 244760)
+               type = PyTango._PyTango.CmdArgType.DevDouble
+              value = array([  0.,   1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,
+                11.,  12.,  13.,  14.,  15.,  16.,  17.,  18.,  19.])
+            w_dim_x = 20
+            w_dim_y = 0
+        w_dimension = AttributeDimension(dim_x = 20, dim_y = 0)
+            w_value = array([  0.,   1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,
+                11.,  12.,  13.,  14.,  15.,  16.,  17.,  18.,  19.])]
+
+        Spock <homer:10000> [5]: # Write a scalar attribute
+        Spock <homer:10000> [6]: scalar_value = 18
+        Spock <homer:10000> [7]: tangotest.write_attribute("long_scalar", scalar_value)
+
+        Spock <homer:10000> [8]: # Write a spectrum attribute
+        Spock <homer:10000> [9]: spectrum_value = numpy.random.rand(100)*10
+        Spock <homer:10000> [10]: tangotest.write_attribute("double_spectrum", spectrum_value)
+        
+        
+        Spock <homer:10000> [11]: # Write an image attribute
+        Spock <homer:10000> [12]: image_value = numpy.random.randint(0,10,size=(10,10))
+        Spock <homer:10000> [13]: tangotest.write_attribute("long_image", image_value)
+
+.. tip::
+    
+    If you are only interested in the attribute's read value you can do insted:
+    
+    .. sourcecode:: spock
+        
+            Spock <homer:10000> [1]: tangotest.long_scalar
+                         Result [1]: 239
+    
+    The same is valid for writting a new value to an attribute:
+    
+    .. sourcecode:: spock
+        
+            Spock <homer:10000> [1]: tangotest.long_scalar = 18
+    
+.. note::
+
+    If PyTango is compiled with numpy support the values got when reading
+    a spectrum or an image will be numpy arrays. This results in a faster and
+    more memory efficient PyTango. You can also use numpy to specify the values when
+    writing attributes, especially if you know the exact attribute type.::
+
+        # Creating an unitialized double spectrum of 1000 elements
+        spectrum_value = PyTango.numpy_spectrum(PyTango.DevDouble, 1000)
+
+        # Creating an spectrum with a range
+        # Note that I do NOT use PyTango.DevLong here, BUT PyTango.NumpyType.DevLong
+        # numpy functions do not understand normal python types, so there's a
+        # translation available in PyTango.NumpyType
+        spectrum_value = numpy.arange(5, 1000, 2, PyTango.NumpyType.DevLong)
+
+        # Creating a 2x2 long image from an existing one
+        image_value = PyTango.numpy_image(PyTango.DevLong, [[1,2],[3,4]])
+
+Registering devices
+~~~~~~~~~~~~~~~~~~~
+
+Defining devices in the Tango DataBase:
+
+    .. sourcecode:: spock
+    
+        Spock <homer:10000> [1]: # The 3 devices name we want to create
+        Spock <homer:10000> [2]: # Note: these 3 devices will be served by the same DServer
+        Spock <homer:10000> [3]: new_device_name1="px1/tdl/mouse1"
+        Spock <homer:10000> [4]: new_device_name2="px1/tdl/mouse2"
+        Spock <homer:10000> [5]: new_device_name3="px1/tdl/mouse3"
+
+        Spock <homer:10000> [6]: # Define the Tango Class served by this DServer
+        Spock <homer:10000> [7]: new_device_info_mouse = PyTango.DbDevInfo()
+        Spock <homer:10000> [8]: new_device_info_mouse._class = "Mouse"
+        Spock <homer:10000> [9]: new_device_info_mouse.server = "ds_Mouse/server_mouse"
+
+        Spock <homer:10000> [10]: # add the first device
+        Spock <homer:10000> [11]: new_device_info_mouse.name = new_device_name1
+        Spock <homer:10000> [12]: db.add_device(new_device_info_mouse)
+
+        Spock <homer:10000> [13]: # add the next device
+        Spock <homer:10000> [14]: new_device_info_mouse.name = new_device_name2
+        Spock <homer:10000> [15]: db.add_device(new_device_info_mouse)
+
+        Spock <homer:10000> [16]: # add the third device
+        Spock <homer:10000> [17]: new_device_info_mouse.name = new_device_name3
+        Spock <homer:10000> [18]: db.add_device(new_device_info_mouse)
+
+Setting up Device properties
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A more complex example using python subtilities.
+The following python script example (containing some functions and instructions
+manipulating a Galil motor axis device server) gives an idea of how the Tango
+API should be accessed from Python.
+
+    .. sourcecode:: spock
+    
+        Spock <homer:10000> [1]: # connecting to the motor axis device
+        Spock <homer:10000> [2]: axis1 = DeviceProxy ("microxas/motorisation/galilbox")
+
+        Spock <homer:10000> [3]: # Getting Device Properties
+        Spock <homer:10000> [4]: property_names = ["AxisBoxAttachement",
+                           ....:                   "AxisEncoderType",
+                           ....:                   "AxisNumber",
+                           ....:                   "CurrentAcceleration",
+                           ....:                   "CurrentAccuracy",
+                           ....:                   "CurrentBacklash",
+                           ....:                   "CurrentDeceleration",
+                           ....:                   "CurrentDirection",
+                           ....:                   "CurrentMotionAccuracy",
+                           ....:                   "CurrentOvershoot",
+                           ....:                   "CurrentRetry",
+                           ....:                   "CurrentScale",
+                           ....:                   "CurrentSpeed",
+                           ....:                   "CurrentVelocity",
+                           ....:                   "EncoderMotorRatio",
+                           ....:                   "logging_level",
+                           ....:                   "logging_target",
+                           ....:                   "UserEncoderRatio",
+                           ....:                   "UserOffset"]
+        
+        Spock <homer:10000> [5]: axis_properties = axis1.get_property(property_names)
+        Spock <homer:10000> [6]: for prop in axis_properties.keys():
+                           ....:     print "%s: %s" % (prop, axis_properties[prop][0])
+
+        Spock <homer:10000> [7]: # Changing Properties
+        Spock <homer:10000> [8]: axis_properties["AxisBoxAttachement"] = ["microxas/motorisation/galilbox"]
+        Spock <homer:10000> [9]: axis_properties["AxisEncoderType"] = ["1"]
+        Spock <homer:10000> [10]: axis_properties["AxisNumber"] = ["6"]
+        Spock <homer:10000> [11]: axis1.put_property(axis_properties)
+
+        Spock <homer:10000> [12]: # Reading attributes
+        Spock <homer:10000> [13]: att_list = axis.get_attribute_list()
+        Spock <homer:10000> [14]: for att in att_list:
+                            ....:     att_val = axis.read_attribute(att)
+                            ....:     print "%s: %s" % (att.name, att_val.value)
+
+        Spock <homer:10000> [15]: # Changing some attribute values
+        Spock <homer:10000> [16]: axis1.write_attribute("AxisBackslash", 0.5)
+        Spock <homer:10000> [17]: axis1.write_attribute("AxisDirection", 1.0)
+        Spock <homer:10000> [18]: axis1.write_attribute("AxisVelocity", 1000.0)
+        Spock <homer:10000> [19]: axis1.write_attribute("AxisOvershoot", 500.0)
+
+        Spock <homer:10000> [20]: # Testing some device commands
+        Spock <homer:10000> [21]: pos1=axis1.read_attribute("AxisCurrentPosition")
+        Spock <homer:10000> [22]: axis1.command_inout("AxisBackward")
+        Spock <homer:10000> [23]: while pos1.value > 1000.0:
+                            ....:     pos1 = axis1.read_attribute("AxisCurrentPosition")
+                            ....:     print "position axis 1 = ", pos1.value
+                            
+        Spock <homer:10000> [24]: axis1.command_inout("AxisStop")
+
+A quick tour of Tango device server binding through an example
+--------------------------------------------------------------
+
+To write a tango device server in python, you need to import two modules in your script which are:
+
+1. The PyTango module
+
+2. The python sys module provided in the classical python distribution
+
+The following in the python script for a Tango device server with two commands and two attributes. The commands are:
+
+1. IOLOng which receives a Tango Long and return it multiply by 2. This command is allowed only if the device is in the ON state.
+
+2. IOStringArray which receives an array of Tango strings and which returns it but in the reverse order. This command is only allowed if the device is in the ON state.
+
+The attributes are:
+
+1. Long_attr wich is a Tango long attribute, Scalar and Read only with a minimum alarm set to 1000 and a maximum alarm set to 1500
+
+2. Short_attr_rw which is a Tango short attribute, Scalar and Read/Write
+
+The following code is the complete device server code::
+
+    import PyTango
+    import sys
+
+    class PyDsExp(PyTango.Device_3Impl):
+
+        def __init__(self,cl,name):
+            PyTango.Device_3Impl.__init__(self,cl,name)
+            self.debug_stream('In PyDsExp __init__')
+            PyDsExp.init_device(self)
+
+        def init_device(self):
+            self.debug_stream('In Python init_device method')
+            self.set_state(PyTango.DevState.ON)
+            self.attr_short_rw = 66
+            self.attr_long = 1246
+
+    #------------------------------------------------------------------
+
+        def delete_device(self):
+            self.debug_stream('[delete_device] for device %s ' % self.get_name())
+
+    #------------------------------------------------------------------
+    # COMMANDS
+    #------------------------------------------------------------------
+
+        def is_IOLong_allowed(self):
+            return self.get_state() == PyTango.DevState.ON
+
+        def IOLong(self, in_data):
+            self.debug_stream('[IOLong::execute] received number %s' % str(in_data))
+            in_data = in_data * 2;
+            self.debug_stream('[IOLong::execute] return number %s' % str(in_data))
+            return in_data;
+
+    #------------------------------------------------------------------
+
+        def is_IOStringArray_allowed(self):
+            return self.get_state() == PyTango.DevState.ON
+
+        def IOStringArray(self, in_data):
+            l = range(len(in_data)-1, -1, -1);
+            out_index=0
+            out_data=[]
+            for i in l:
+                self.debug_stream('[IOStringArray::execute] received String' % in_data[out_index])
+                out_data.append(in_data[i])
+                self.debug_stream('[IOStringArray::execute] return String %s' %out_data[out_index])
+                out_index += 1
+            self.y = out_data
+            return out_data
+
+    #------------------------------------------------------------------
+    # ATTRIBUTES
+    #------------------------------------------------------------------
+
+        def read_attr_hardware(self, data):
+            self.debug_stream('In read_attr_hardware')
+
+    #------------------------------------------------------------------
+
+        def read_Long_attr(self, the_att):
+            self.debug_stream('[PyDsExp::read_attr] attribute name Long_attr')
+
+            # Before PyTango 7.0.0
+            #PyTango.set_attribute_value(the_att, self.attr_long)
+
+            # Now:
+            the_att.set_value(self.attr_long)
+
+    #------------------------------------------------------------------
+
+        def read_Short_attr_rw(self, the_att):
+            self.debug_stream('[PyDsExp::read_attr] attribute name Short_attr_rw')
+
+            # Before PyTango 7.0.0
+            #PyTango.set_attribute_value(the_att, self.attr_short_rw)
+            
+            # Now:
+            the_att.set_value(self.attr_short_rw)
+
+    #------------------------------------------------------------------
+
+        def write_Short_attr_rw(self, the_att):
+            self.debug_stream('In write_Short_attr_rw for attribute %s' % the_att.get_name())
+
+            # Before PyTango 7.0.0
+            #data = []
+            #PyTango.get_write_value(the_att, data)
+
+            # Now:
+            data = the_att.get_write_value()
+            self.attr_short_rw = data[0]
+
+    #------------------------------------------------------------------
+    # CLASS
+    #------------------------------------------------------------------
+
+    class PyDsExpClass(PyTango.DeviceClass):
+
+        def __init__(self, name):
+            PyTango.DeviceClass.__init__(self, name)
+            self.set_type("TestDevice")
+            print 'In PyDsExpClass __init__'
+
+        cmd_list = { 'IOLong' : [ [ PyTango.ArgType.DevLong, "Number" ],
+                                  [ PyTango.ArgType.DevLong, "Number * 2" ] ],
+                     'IOStringArray' : [ [ PyTango.ArgType.DevVarStringArray, "Array of string" ],
+                                         [ PyTango.ArgType.DevVarStringArray, "This reversed array"] ],
+        }
+
+        attr_list = { 'Long_attr' : [ [ PyTango.ArgType.DevLong ,
+                                        PyTango.AttrDataFormat.SCALAR ,
+                                        PyTango.AttrWriteType.READ],
+                                      { 'min alarm' : 1000, 'max alarm' : 1500 } ],
+
+                     'Short_attr_rw' : [ [ PyTango.ArgType.DevShort,
+                                           PyTango.AttrDataFormat.SCALAR,
+                                           PyTango.AttrWriteType.READ_WRITE ] ]
+        }
+
+    if __name__ == '__main__':
+        try:
+            util = PyTango.Util(sys.argv)
+            
+            # 
+            # Deprecated: util.add_TgClass(PyDsExpClass, PyDsExp, 'PyDsExp')
+            util.add_class(PyDsExpClass, PyDsExp, 'PyDsExp')
+            
+            U = PyTango.Util.instance()
+            U.server_init()
+            U.server_run()
+        except PyTango.DevFailed,e:
+            print '-------> Received a DevFailed exception:',e
+        except Exception,e:
+            print '-------> An unforeseen exception occured....',e
+
+.. _IPython: http://ipython.scipy.org/
\ No newline at end of file
diff --git a/doc/quicktour_old.rst b/doc/quicktour_old.rst
new file mode 100644
index 0000000..fc8633e
--- /dev/null
+++ b/doc/quicktour_old.rst
@@ -0,0 +1,439 @@
+.. _quick-tour-old:
+
+A quick tour (original)
+-----------------------
+
+This quick tour will guide you through the first steps on using PyTango.
+This is the original quick tour guide that uses a simple Python console.
+There is a new version of this document which uses :ref:`spock` console in its
+examples. You can find this new version :ref:`here <quick-tour>`.
+
+Check PyTango version
+~~~~~~~~~~~~~~~~~~~~~
+
+Start a python console and type:
+
+    >>> import PyTango
+    >>> PyTango.__version__
+    '7.1.2'
+    >>> PyTango.__version_long__
+    '7.1.2dev0'
+    >>> PyTango.__version_number__
+    712
+    >>> PyTango.__version_description__
+    'This version implements the C++ Tango 7.1 API.'
+
+or alternatively:
+
+    >>> import PyTango
+    >>> PyTango.Release.version
+    '7.1.2'
+    >>> PyTango.Release.version_long
+    '7.1.2dev0'
+    >>> PyTango.Release.version_number
+    712
+    >>> PyTango.Release.version_description
+    'This version implements the C++ Tango 7.1 API.'
+
+Check Tango C++ version
+~~~~~~~~~~~~~~~~~~~~~~~
+
+From a client (This is only possible since PyTango 7.0.0)
+
+    >>> import PyTango.constants
+    >>> PyTango.constants.TgLibVers
+    '7.1.1'
+    
+From a server you can alternatively do::
+    
+    u = PyTango.Util.instance()
+    tg_cpp_lib_ver = u.get_tango_lib_release()
+    
+
+Test the connection to the Device and get it's current state
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+One of the most basic examples is to get a reference to a device and
+determine if it is running or not::
+
+    from PyTango import *
+    import sys, os, time
+
+    # Protect the script from Exceptions
+    try:
+            # Get proxy on the tangotest1 device
+            print "Getting DeviceProxy "
+            tangotest = DeviceProxy("tango/tangotest/1")
+
+            # ping it
+            print tangotest.ping()
+            
+            # get the state
+            print tangotest.state()
+            
+            # First use the classical command_inout way to execute the DevString command
+            # (DevString in this case is a command of the TangoTest device)
+
+            result= tangotest.command_inout("DevString", "First hello to device")
+            print "Result of execution of DevString command=", result
+
+            # the same with a Device specific command
+            result= tangotest.DevString("Second Hello to device")
+            print "Result of execution of DevString command=", result
+
+            # Please note that argin argument type is automagically managed by python
+            result= tangotest.DevULong(12456)
+            print "Result of execution of DevULong command=", result
+
+    # Catch Tango and Systems  Exceptions
+    except:
+            print "Failed with exception !"
+            print sys.exc_info()[0]
+
+Execute commands with scalar arguments on a Device
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+As you can see in the following example, when scalar types are used, the Tango
+binding automagically manages the data types, and writing scripts is quite easy::
+
+    from PyTango import *
+    import sys, os, time
+
+    tangotest = DeviceProxy("tango/tangotest/1")
+
+    # First use the classical command_inout way to execute the DevString command
+    # (DevString in this case is a command of the TangoTest device)
+
+    result= tangotest.command_inout("DevString", "First hello to device")
+    print "Result of execution of DevString command=", result
+
+    # the same with a Device specific command
+    result= tangotest.DevString("Second Hello to device")
+    print "Result of execution of DevString command=", result
+
+    # Please note that argin argument type is automagically managed by python
+    result= tangotest.DevULong(12456)
+    print "Result of execution of DevULong command=", result
+
+Execute commands with more complex types
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In this case you have to use put your arguments data in the correct python
+structures::
+
+    from PyTango import *
+    import sys, os, time
+
+    print "Getting DeviceProxy "
+    tango_test = DeviceProxy("tango/tangotest/1")
+    # The input argument is a DevVarLongStringArray
+    # so create the argin variable containing
+    # an array of longs and an array of strings
+    argin = ([1,2,3], ["Hello", "TangoTest device"])
+
+    result= tango_test.DevVarLongArray(argin)
+    print "Result of execution of DevVarLongArray command=", result
+
+Reading and writing attributes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Basic read/write attribute operations::
+
+    #Read a scalar attribute
+    scalar=tangotest.read_attribute("long_scalar")
+
+    #Read a spectrum attribute
+    spectrum=tangotest.read_attribute("double_spectrum")
+
+    # Write a scalar attribute
+    scalar_value = 18
+    tangotest.write_attribute("long_scalar", scalar_value)
+
+    # Write a spectrum attribute
+    spectrum_value = [1.2, 3.2, 12.3]
+    tangotest.write_attribute("double_spectrum", spectrum_value)
+
+    # Write an image attribute
+    image_value = [ [1, 2], [3, 4] ]
+    tangotest.write_attribute("long_image", image_value)
+
+
+Note that if PyTango is compiled with numpy support the values got when reading
+a spectrum or an image will be numpy arrays. This results in a faster and
+more memory efficient PyTango. You can also use numpy to specify the values when
+writing attributes, especially if you know the exact attribute type.::
+
+    import PyTango, numpy
+
+    # Creating an unitialized double spectrum of 1000 elements
+    spectrum_value = PyTango.numpy_spectrum(PyTango.DevDouble, 1000)
+
+    # Creating an spectrum with a range
+    # Note that I do NOT use PyTango.DevLong here, BUT PyTango.NumpyType.DevLong
+    # numpy functions do not understand normal python types, so there's a
+    # translation available in PyTango.NumpyType
+    spectrum_value = numpy.arange(5, 1000, 2, PyTango.NumpyType.DevLong)
+
+    # Creating a 2x2 long image from an existing one
+    image_value = PyTango.numpy_image(PyTango.DevLong, [[1,2],[3,4]])
+
+
+Registering devices
+~~~~~~~~~~~~~~~~~~~
+
+Defining devices in the Tango DataBase::
+
+    from PyTango import *
+    import sys, os, time
+
+    #  A reference on the DataBase
+    db = Database()
+
+    # The 3 devices name we want to create
+    # Note: these 3 devices will be served by the same DServer
+    new_device_name1="px1/tdl/mouse1"
+    new_device_name2="px1/tdl/mouse2"
+    new_device_name3="px1/tdl/mouse3"
+
+    # Define the Tango Class served by this  DServer
+    new_device_info_mouse = DbDevInfo()
+    new_device_info_mouse._class = "Mouse"
+    new_device_info_mouse.server = "ds_Mouse/server_mouse"
+
+    # add the first device
+    print "Creation Device:" , new_device_name1
+    new_device_info_mouse.name = new_device_name1
+    db.add_device(new_device_info_mouse)
+
+    # add the next device
+    print "Creation Device:" , new_device_name2
+    new_device_info_mouse.name = new_device_name2
+    db.add_device(new_device_info_mouse)
+    # add the third device
+    print "Creation Device:" , new_device_name3
+    new_device_info_mouse.name = new_device_name3
+    db.add_device(new_device_info_mouse)
+
+
+Setting up Device properties
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+A more complex example using python subtilities.
+The following python script example (containing some functions and instructions
+manipulating a Galil motor axis device server) gives an idea of how the Tango
+API should be accessed from Python::
+
+    from PyTango import *
+    import sys, os, time
+
+    # connecting to the motor axis device
+    axis1 = DeviceProxy ("microxas/motorisation/galilbox")
+
+    # Getting Device Properties
+    property_names = ["AxisBoxAttachement",
+                      "AxisEncoderType",
+                      "AxisNumber",
+                      "CurrentAcceleration",
+                      "CurrentAccuracy",
+                      "CurrentBacklash",
+                      "CurrentDeceleration",
+                      "CurrentDirection",
+                      "CurrentMotionAccuracy",
+                      "CurrentOvershoot",
+                      "CurrentRetry",
+                      "CurrentScale",
+                      "CurrentSpeed",
+                      "CurrentVelocity",
+                      "EncoderMotorRatio",
+                      "logging_level",
+                      "logging_target",
+                      "UserEncoderRatio",
+                      "UserOffset"]
+    axis_properties = axis1.get_property(property_names)
+    for prop in axis_properties.keys():
+        print "%s: %s" % (prop, axis_properties[prop][0])
+
+    # Changing Properties
+    axis_properties["AxisBoxAttachement"] = ["microxas/motorisation/galilbox"]
+    axis_properties["AxisEncoderType"] = ["1"]
+    axis_properties["AxisNumber"] = ["6"]
+    axis1.put_property(axis_properties)
+
+    # Reading attributes
+    att_list = axis.get_attribute_list()
+    for att in att_list:
+        att_val = axis.read_attribute(att)
+        print "%s: %s" % (att, att_val.value)
+
+    # Changing some attribute values
+    axis1.write_attribute("AxisBackslash", 0.5)
+    axis1.write_attribute("AxisDirection", 1.0)
+    axis1.write_attribute("AxisVelocity", 1000.0)
+    axis1.write_attribute("AxisOvershoot", 500.0)
+
+    # Testing some device commands
+    pos1=axis1.read_attribute("AxisCurrentPosition")
+    axis1.command_inout("AxisBackward")
+    while pos1.value > 1000.0:
+        pos1=axis1.read_attribute("AxisCurrentPosition")
+        print "position axis 1 = ",pos1.value
+    axis1.command_inout("AxisStop")
+
+A quick tour of Tango device server binding through an example
+--------------------------------------------------------------
+
+To write a tango device server in python, you need to import two modules in your script which are:
+
+1. The PyTango module
+
+2. The python sys module provided in the classical python distribution
+
+The following in the python script for a Tango device server with two commands and two attributes. The commands are:
+
+1. IOLOng which receives a Tango Long and return it multiply by 2. This command is allowed only if the device is in the ON state.
+
+2. IOStringArray which receives an array of Tango strings and which returns it but in the reverse order. This command is only allowed if the device is in the ON state.
+
+The attributes are:
+
+1. Long_attr wich is a Tango long attribute, Scalar and Read only with a minimum alarm set to 1000 and a maximum alarm set to 1500
+
+2. Short_attr_rw which is a Tango short attribute, Scalar and Read/Write
+
+The following code is the complete device server code::
+
+    import PyTango
+    import sys
+
+    class PyDsExp(PyTango.Device_3Impl):
+
+        def __init__(self,cl,name):
+            PyTango.Device_3Impl.__init__(self,cl,name)
+            self.debug_stream('In PyDsExp __init__')
+            PyDsExp.init_device(self)
+
+        def init_device(self):
+            self.debug_stream('In Python init_device method')
+            self.set_state(PyTango.DevState.ON)
+            self.attr_short_rw = 66
+            self.attr_long = 1246
+
+    #------------------------------------------------------------------
+
+        def delete_device(self):
+            self.debug_stream('[delete_device] for device %s ' % self.get_name())
+
+    #------------------------------------------------------------------
+    # COMMANDS
+    #------------------------------------------------------------------
+
+        def is_IOLong_allowed(self):
+            return self.get_state() == PyTango.DevState.ON
+
+        def IOLong(self, in_data):
+            self.debug_stream('[IOLong::execute] received number %s' % str(in_data))
+            in_data = in_data * 2;
+            self.debug_stream('[IOLong::execute] return number %s' % str(in_data))
+            return in_data;
+
+    #------------------------------------------------------------------
+
+        def is_IOStringArray_allowed(self):
+            return self.get_state() == PyTango.DevState.ON
+
+        def IOStringArray(self, in_data):
+            l = range(len(in_data)-1, -1, -1);
+            out_index=0
+            out_data=[]
+            for i in l:
+                self.debug_stream('[IOStringArray::execute] received String' % in_data[out_index])
+                out_data.append(in_data[i])
+                self.debug_stream('[IOStringArray::execute] return String %s' %out_data[out_index])
+                out_index += 1
+            self.y = out_data
+            return out_data
+
+    #------------------------------------------------------------------
+    # ATTRIBUTES
+    #------------------------------------------------------------------
+
+        def read_attr_hardware(self, data):
+            self.debug_stream('In read_attr_hardware')
+
+    #------------------------------------------------------------------
+
+        def read_Long_attr(self, the_att):
+            self.debug_stream('[PyDsExp::read_attr] attribute name Long_attr')
+
+            # Before PyTango 7.0.0
+            #PyTango.set_attribute_value(the_att, self.attr_long)
+
+            # Now:
+            the_att.set_value(self.attr_long)
+
+    #------------------------------------------------------------------
+
+        def read_Short_attr_rw(self, the_att):
+            self.debug_stream('[PyDsExp::read_attr] attribute name Short_attr_rw')
+
+            # Before PyTango 7.0.0
+            #PyTango.set_attribute_value(the_att, self.attr_short_rw)
+            
+            # Now:
+            the_att.set_value(self.attr_short_rw)
+
+    #------------------------------------------------------------------
+
+        def write_Short_attr_rw(self, the_att):
+            self.debug_stream('In write_Short_attr_rw for attribute %s' % the_att.get_name())
+
+            # Before PyTango 7.0.0
+            #data = []
+            #PyTango.get_write_value(the_att, data)
+
+            # Now:
+            data = the_att.get_write_value()
+            self.attr_short_rw = data[0]
+
+    #------------------------------------------------------------------
+    # CLASS
+    #------------------------------------------------------------------
+
+    class PyDsExpClass(PyTango.DeviceClass):
+
+        def __init__(self, name):
+            PyTango.DeviceClass.__init__(self, name)
+            self.set_type("TestDevice")
+            print 'In PyDsExpClass __init__'
+
+        cmd_list = { 'IOLong' : [ [ PyTango.ArgType.DevLong, "Number" ],
+                                  [ PyTango.ArgType.DevLong, "Number * 2" ] ],
+                     'IOStringArray' : [ [ PyTango.ArgType.DevVarStringArray, "Array of string" ],
+                                         [ PyTango.ArgType.DevVarStringArray, "This reversed array"] ],
+        }
+
+        attr_list = { 'Long_attr' : [ [ PyTango.ArgType.DevLong ,
+                                        PyTango.AttrDataFormat.SCALAR ,
+                                        PyTango.AttrWriteType.READ],
+                                      { 'min alarm' : 1000, 'max alarm' : 1500 } ],
+
+                     'Short_attr_rw' : [ [ PyTango.ArgType.DevShort,
+                                           PyTango.AttrDataFormat.SCALAR,
+                                           PyTango.AttrWriteType.READ_WRITE ] ]
+        }
+
+    if __name__ == '__main__':
+        try:
+            util = PyTango.Util(sys.argv)
+            
+            # 
+            # Deprecated: util.add_TgClass(PyDsExpClass, PyDsExp, 'PyDsExp')
+            util.add_class(PyDsExpClass, PyDsExp, 'PyDsExp')
+            
+            U = PyTango.Util.instance()
+            U.server_init()
+            U.server_run()
+        except PyTango.DevFailed,e:
+            print '-------> Received a DevFailed exception:',e
+        except Exception,e:
+            print '-------> An unforeseen exception occured....',e
diff --git a/doc/revision.rst b/doc/revision.rst
new file mode 100644
index 0000000..4e9c2b8
--- /dev/null
+++ b/doc/revision.rst
@@ -0,0 +1,160 @@
+.. _revision:
+
+Revision
+--------
+
+:Contributers: T\. Coutinho
+
+:Last Update: |today|
+
+.. _history-modifications:
+
+History of modifications:
+
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+|   Date   | Revision                                                                         |                          Description                | Author                |
++==========+==================================================================================+=====================================================+=======================+
+| 18/07/03 | 1.0                                                                              | Initial Version                                     | M\. Ounsy             |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+| 06/10/03 | 2.0                                                                              | Extension of the "Getting Started" paragraph        | A\. Buteau/M\. Ounsy  |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+| 14/10/03 | 3.0                                                                              | Added Exception Handling paragraph                  | M\. Ounsy             |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+| 13/06/05 | 4.0                                                                              | Ported to Latex, added events, AttributeProxy       | V\. Forchì            |
+|          |                                                                                  | and ApiUtil                                         |                       |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+|          |                                                                                  | fixed bug with python 2.5 and and state events      |                       |
+| 13/06/05 | 4.1                                                                              | new Database constructor                            | V\. Forchì            |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+| 15/01/06 | 5.0                                                                              | Added Device Server classes                         | E\.Taurel             |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+| 15/03/07 | 6.0                                                                              | Added AttrInfoEx, AttributeConfig events, 64bits,   | T\. Coutinho          |
+|          |                                                                                  | write_attribute                                     |                       |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+| 21/03/07 | 6.1                                                                              | Added groups                                        | T\. Coutinho          |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+| 15/06/07 | `6.2 <http://www.tango-controls.org/Documents/bindings/PyTango-3.0.3.pdf>`_      | Added dynamic attributes doc                        | E\. Taurel            |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+| 06/05/08 | `7.0 <http://www.tango-controls.org/Documents/bindings/PyTango-3.0.4.pdf>`_      | Update to Tango 6.1. Added DB methods, version info | T\. Coutinho          |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+| 10/07/09 | `8.0 <http://www.tango-controls.org/static/PyTango/v7/doc/html/index.html>`_     | Update to Tango 7. Major refactoring. Migrated doc  | T\. Coutinho/R\. Suñe |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+| 24/07/09 | `8.1 <http://www.tango-controls.org/static/PyTango/v7/doc/html/index.html>`_     | Added migration info, added missing API doc         | T\. Coutinho/R\. Suñe |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+| 21/09/09 | `8.2 <http://www.tango-controls.org/static/PyTango/v7/doc/html/index.html>`_     | Added migration info, release of 7.0.0beta2         | T\. Coutinho/R\. Suñe |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+| 12/11/09 | `8.3 <http://www.tango-controls.org/static/PyTango/v71/doc/html/index.html>`_    | Update to Tango 7.1.                                | T\. Coutinho/R\. Suñe |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+| ??/12/09 | `8.4 <http://www.tango-controls.org/static/PyTango/v71rc1/doc/html/index.html>`_ | Update to PyTango 7.1.0 rc1                         | T\. Coutinho/R\. Suñe |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+| 19/02/10 | `8.5 <http://www.tango-controls.org/static/PyTango/v711/doc/html/index.html>`_   | Update to PyTango 7.1.1                             | T\. Coutinho/R\. Suñe |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+| 06/08/10 | `8.6 <http://www.tango-controls.org/static/PyTango/v712/doc/html/index.html>`_   | Update to PyTango 7.1.2                             | T\. Coutinho          |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+| 05/11/10 | `8.7 <http://www.tango-controls.org/static/PyTango/v712/doc/html/index.html>`_   | Update to PyTango 7.1.3                             | T\. Coutinho          |
++----------+----------------------------------------------------------------------------------+-----------------------------------------------------+-----------------------+
+
+.. _version-history:
+
+Version history
+---------------
+
++------------+-------------------------------------------------------------------------------------+
+| version    | Changes                                                                             |
++============+=====================================================================================+
+| 7.1.3      | Features:                                                                           |
+|            |     - tango logging with print statement                                            |
+|            |     - tango logging with decorators                                                 |
+|            |     - from sourceforge:                                                             |
+|            |         - 3060380: ApiUtil should be exported to PyTango                            |
+|            |                                                                                     |
+|            | Bug fixes:                                                                          |
+|            |     - added licence header to all source code files                                 |
+|            |     - spock didn't work without TANGO_HOST env. variable (it didn't recognize       |
+|            |       tangorc)                                                                      |
+|            |     - spock should give a proper message if it tries to be initialized outside      |
+|            |       ipython                                                                       |
+|            |     - from sourceforge:                                                             |
+|            |         - 3048798: licence issue GPL != LGPL                                        |
+|            |         - 3073378: DeviceImpl.signal_handler raising exception crashes DS           |
+|            |         - 3088031: Python DS unable to read DevVarBooleanArray property             |
+|            |         - 3102776: PyTango 7.1.2 does not work with python 2.4 & boost 1.33.0       |
+|            |         - 3102778: Fix compilation warnings in linux                                |
++------------+-------------------------------------------------------------------------------------+
+| 7.1.2      | Features:                                                                           |
+|            |     - from sourceforge:                                                             |
+|            |         - 2995964: Dynamic device creation                                          |
+|            |         - 3010399: The DeviceClass.get_device_list that exists in C++ is missing    |
+|            |         - 3023686: Missing DeviceProxy.<attribute name>                             |
+|            |         - 3025396: DeviceImpl is missing some CORBA methods                         |
+|            |         - 3032005: IPython extension for PyTango                                    |
+|            |         - 3033476: Make client objects pickable                                     |
+|            |         - 3039902: PyTango.Util.add_class would be useful                           |
+|            |                                                                                     |
+|            | Bug fixes:                                                                          |
+|            |     - from sourceforge:                                                             |
+|            |         - 2975940: DS command with DevVarCharArray return type fails                |
+|            |         - 3000467: DeviceProxy.unlock is LOCKING instead of unlocking!              |
+|            |         - 3010395: Util.get_device_* methods don't work                             |
+|            |         - 3010425: Database.dev_name does not work                                  |
+|            |         - 3016949: command_inout_asynch callback does not work                      |
+|            |         - 3020300: PyTango does not compile with gcc 4.1.x                          |
+|            |         - 3030399: Database put(delete)_attribute_alias generates segfault          |
++------------+-------------------------------------------------------------------------------------+
+| 7.1.1      | Features:                                                                           |
+|            |     - Improved setup script                                                         |
+|            |     - Interfaced with PyPI                                                          |
+|            |     - Cleaned build script warnings due to unclean python C++ macro definitions     |
+|            |     - from sourceforge: 2985993, 2971217                                            |
+|            |                                                                                     |
+|            | Bug fixes:                                                                          |
+|            |     - from sourceforge: 2983299, 2953689, 2953030                                   |
++------------+-------------------------------------------------------------------------------------+
+| 7.1.0      | Features:                                                                           |
+|            |     - from sourceforge:                                                             |
+|            |       - 2908176: read_*, write_* and is_*_allowed() methods can now be defined      |
+|            |       - 2941036: TimeVal conversion to time and datetime                            |
+|            |     - added str representation on Attr, Attribute, DeviceImpl and DeviceClass       |
+|            |                                                                                     |
+|            | Bug fixes:                                                                          |
+|            |     - from sourceforge: 2903755, 2908176, 2914194, 2909927, 2936173, 2949099        |
++------------+-------------------------------------------------------------------------------------+
+| 7.1.0rc1   | Features:                                                                           |
+|            |     - v = image_attribute.get_write_value() returns square sequences (arrays of     |
+|            |       arrays, or numpy objects) now instead of flat lists. Also for spectrum        |
+|            |       attributes a numpy is returned by default now instead.                        |
+|            |     - image_attribute.set_value(v) accepts numpy arrays now or square sequences     |
+|            |       instead of just flat lists. So, dim_x and dim_y are useless now. Also the     |
+|            |       numpy path is faster.                                                         |
+|            |     - new enum AttrSerialModel                                                      |
+|            |     - Attribute new methods: set(get)_attr_serial_model, set_change_event,          |
+|            |       set_archive_event, is_change_event, is_check_change_event,                    |
+|            |       is_archive_criteria, is_check_archive_criteria, remove_configuration          |
+|            |     - added support for numpy scalars in tango operations like write_attribute      |
+|            |       (ex: now a DEV_LONG attribute can receive a numpy.int32 argument in a         |
+|            |       write_attribute method call)                                                  |
+|            |                                                                                     |
+|            | Bug fixes:                                                                          |
+|            |     - DeviceImpl.set_value for scalar attributes                                    |
+|            |     - DeviceImpl.push_***_event                                                     |
+|            |     - server commands with DevVar***StringArray as parameter or as return type      |
+|            |     - in windows,a bug in PyTango.Util prevented servers from starting up           |
+|            |     - DeviceImpl.get_device_properties for string properties assigns only first     |
+|            |       character of string to object member instead of entire string                 |
+|            |     - added missing methods to Util                                                 |
+|            |     - exported SubDevDiag class                                                     |
+|            |     - error in read/events of attributes of type DevBoolean READ_WRITE              |
+|            |     - error in automatic unsubscribe events of DeviceProxy when the object          |
+|            |       disapears (happens only on some compilers with some optimization flags)       |
+|            |     - fix possible bug when comparing attribute names in DeviceProxy                |
+|            |     - pretty print of DevFailed -> fix deprecation warning in python 2.6            |
+|            |     - device class properties where not properly fetched when there is no           |
+|            |       property value defined                                                        |
+|            |     - memory leak when converting DevFailed exceptions from C++ to python           |
+|            |     - python device server file without extension does not start                    |
+|            |                                                                                     |
+|            | Documentation:                                                                      |
+|            |     - Improved FAQ                                                                  |
+|            |     - Improved compilation chapter                                                  |
+|            |     - Improved migration information                                                |
++------------+-------------------------------------------------------------------------------------+
diff --git a/doc/server/attribute.rst b/doc/server/attribute.rst
new file mode 100644
index 0000000..756dffb
--- /dev/null
+++ b/doc/server/attribute.rst
@@ -0,0 +1,34 @@
+Attribute classes
+=================
+
+.. currentmodule:: PyTango
+
+Attr
+----
+
+.. autoclass:: PyTango.Attr
+    :members:
+
+Attribute
+---------
+
+.. autoclass:: PyTango.Attribute
+    :members:
+
+WAttribute
+----------
+
+.. autoclass:: PyTango.WAttribute
+    :members:
+
+MultiAttribute
+--------------
+
+.. autoclass:: PyTango.MultiAttribute
+    :members:
+    
+UserDefaultAttrProp
+-------------------
+
+.. autoclass:: PyTango.UserDefaultAttrProp
+    :members:
diff --git a/doc/server/device.rst b/doc/server/device.rst
new file mode 100644
index 0000000..0815b24
--- /dev/null
+++ b/doc/server/device.rst
@@ -0,0 +1,41 @@
+Device classes
+==============
+
+.. currentmodule:: PyTango
+
+DeviceImpl
+----------
+
+.. autoclass:: PyTango.DeviceImpl
+    :members:
+
+Device_2Impl
+------------
+
+.. autoclass:: PyTango.Device_2Impl
+    :show-inheritance:
+    :inherited-members:
+    :members:
+
+Device_3Impl
+------------
+
+.. autoclass:: PyTango.Device_3Impl
+    :show-inheritance:
+    :inherited-members:
+    :members:
+
+Device_4Impl
+------------
+
+.. autoclass:: PyTango.Device_4Impl
+    :show-inheritance:
+    :inherited-members:
+    :members:
+
+DServer
+----------
+
+.. autoclass:: PyTango.DServer
+    :show-inheritance:
+    :members:
diff --git a/doc/server/device_class.rst b/doc/server/device_class.rst
new file mode 100644
index 0000000..71c4723
--- /dev/null
+++ b/doc/server/device_class.rst
@@ -0,0 +1,7 @@
+DeviceClass
+===========
+
+.. currentmodule:: PyTango
+
+.. autoclass:: PyTango.DeviceClass
+    :members:
diff --git a/doc/server/index.rst b/doc/server/index.rst
new file mode 100644
index 0000000..df1d033
--- /dev/null
+++ b/doc/server/index.rst
@@ -0,0 +1,877 @@
+
+.. currentmodule:: PyTango
+
+.. highlight:: python
+   :linenothreshold: 3
+   
+The Tango Device Server Python API
+==================================
+
+This chapter does not explain what a Tango device or a device server is. 
+This is explained in details in "The Tango control system manual" available at 
+http://www.tango-controls.org/TangoKernel.
+The device server we will detailed in the following example is a Tango device 
+server with one Tango class called PyDsExp. This class has two commands called 
+IOLong and IOStringArray and two attributes called Long_attr and Short_attr_rw.
+
+Importing python modules
+------------------------
+
+To write a Python script which is a Tango device server, you need to import 
+two modules which are:
+
+1. The :mod:`PyTango` module which is the Python to C++ interface
+2. The Python classical sys module
+
+This could be done with code like (supposing the PYTHONPATH environment variable
+is correctly set)::
+
+    import PyTango
+    import sys
+
+The main part of a Python device server
+---------------------------------------
+
+The rule of this part of a Tango device server is to:
+    - Create the :class:`Util` object passing it the Python interpreter command line arguments
+    - Add to this object the list of Tango class(es) which have to be hosted by this interpreter
+    - Initialize the device server
+    - Run the device server loop
+
+The following is a typical code for this main function::
+
+    if __name__ == '__main__':
+        util = PyTango.Util(sys.argv)
+        #Deprecated : util.add_TgClass(PyDsExpClass, PyDsExp, 'PyDsExp')
+        util.add_class(PyDsExpClass, PyDsExp)
+        
+        U = PyTango.Util.instance()
+        U.server_init()
+        U.server_run()
+
+**Line 2**
+    Create the Util object passing it the interpreter command line arguments
+**Line 4**
+    Add the Tango class *PyDsExp* to the device server. The :meth:`Util.add_class`
+    method of the Util class has two arguments which are the Tango class 
+    PyDsExpClass instance and the Tango PyDsExp instance.
+    This :meth:`Util.add_class` method is only available since version 
+    7.1.2. If you are using an older version please use 
+    :meth:`Util.add_TgClass` instead.
+**Line 7**
+    Initialize the Tango device server
+**Line 8**
+    Run the device server loop
+
+The PyDsExpClass class in Python
+--------------------------------
+
+The rule of this class is to :
+- Host and manage data you have only once for the Tango class whatever devices of this class will be created
+- Define Tango class command(s)
+- Define Tango class attribute(s)
+
+In our example, the code of this Python class looks like::
+
+    class PyDsExpClass(PyTango.DeviceClass):
+
+        cmd_list = { 'IOLong' : [ [ PyTango.ArgType.DevLong, "Number" ],
+                                  [ PyTango.ArgType.DevLong, "Number * 2" ] ],
+                     'IOStringArray' : [ [ PyTango.ArgType.DevVarStringArray, "Array of string" ],
+                                         [ PyTango.ArgType.DevVarStringArray, "This reversed array"] ],
+        }
+
+        attr_list = { 'Long_attr' : [ [ PyTango.ArgType.DevLong ,
+                                        PyTango.AttrDataFormat.SCALAR ,
+                                        PyTango.AttrWriteType.READ],
+                                      { 'min alarm' : 1000, 'max alarm' : 1500 } ],
+
+                     'Short_attr_rw' : [ [ PyTango.ArgType.DevShort,
+                                           PyTango.AttrDataFormat.SCALAR,
+                                           PyTango.AttrWriteType.READ_WRITE ] ]
+        }
+
+        
+
+**Line 1** 
+    The PyDsExpClass class has to inherit from the PyTango.PyDeviceClass class
+    
+**Line 3 to 7**
+    Definition of the cmd_list dictionnary defining commands. The IOLong command 
+    is defined at lines 3 and 4. The IOStringArray command is defined in line 5 and 6
+**Line 10 to 16**
+    Definition of the attr_list dictionnary defining attributes. The Long_attr 
+    attribute is defined at lines 8 to 11 and the Short_attr_rw attribute is 
+    defined at lines 13 to 15
+    
+If you have something specific to do in the class constructor like
+initializing some specific data member, you will have to code a class 
+constructor. An example of such a contructor is ::
+
+    def __init__(self, name):
+        PyTango.DeviceClass.__init__(self, name)
+        self.set_type("TestDevice")
+
+The device type is set at line 3.
+
+Defining commands
+-----------------
+
+As shown in the previous example, commands have to be defined in a dictionary called *cmd_list* as a data
+member of the xxxClass class of the Tango class. This dictionary has one element per command. The element
+key is the command name. The element value is a Python list which defines the command. The generic form
+of a command definition is:
+    
+    ``'cmd_name' : [ [in_type, <"In desc">], [out_type, <"Out desc">], <{opt parameters}>]``
+
+The first element of the value list is itself a list with the command input data type (one of the PyTango.ArgType
+pseudo enumeration value) and optionally a string describing this input argument. The second element of the
+value list is also a list with the command output data type (one of the PyTango.ArgType pseudo enumeration
+value) and optionally a string describing it.        These two elements are mandatory.   The third list element is
+optional and allows additional command definition. The authorized element for this dictionary are summarized
+in the following array:
+
+    +-------------------+----------------------+------------------------------------------+
+    |      key          |        Value         |             Definition                   |
+    +===================+======================+==========================================+
+    | "display level"   | DispLevel enum value |       The command display level          |
+    +-------------------+----------------------+------------------------------------------+
+    | "polling period"  | Any number           |     The command polling period (mS)      |
+    +-------------------+----------------------+------------------------------------------+
+    | "default command" | True or False        | To define that it is the default command |
+    +-------------------+----------------------+------------------------------------------+
+
+Defining attributes
+-------------------
+
+                                                                                         
+As shown in the previous example, attributes have to be defined in a dictionary called **attr_list** as a data
+member of the xxxClass class of the Tango class. This dictionary has one element per attribute. The element
+key is the attribute name. The element value is a Python list which defines the attribute. The generic form of
+an attribute definition is:
+
+    ``'attr_name' : [ [mandatory parameters], <{opt parameters}>]``
+
+For any kind of attributes, the mandatory parameters are:
+
+    ``[attr data type, attr data format, attr data R/W type]``
+    
+The attribute data type is one of the possible value for attributes of the PyTango.ArgType pseudo enunmeration.
+The attribute data format is one of the possible value of the PyTango.AttrDataFormat pseudo enumeration and
+the attribute R/W type is one of the possible value of the PyTango.AttrWriteType pseudo enumeration. For
+spectrum attribute, you have to add the maximum X size (a number). For image attribute, you have to add
+the maximun X and Y dimension (two numbers). The authorized elements for the dictionnary defining optional
+parameters are summarized in the following array
+
++-------------------+-----------------------------------+------------------------------------------+
+|       key         |              value                |            definition                    |
++===================+===================================+==========================================+
+| "display level"   | PyTango.DispLevel enum value      |   The attribute display level            |
++-------------------+-----------------------------------+------------------------------------------+
+|"polling period"   |          Any number               | The attribute polling period (mS)        |
++-------------------+-----------------------------------+------------------------------------------+
+|  "memorized"      | True or True_without_hard_applied | Define if and how the att. is memorized  |
++-------------------+-----------------------------------+------------------------------------------+
+|     "label"       |            A string               |       The attribute label                |
++-------------------+-----------------------------------+------------------------------------------+
+|  "description"    |            A string               |   The attribute description              |
++-------------------+-----------------------------------+------------------------------------------+
+|     "unit"        |            A string               |       The attribute unit                 |
++-------------------+-----------------------------------+------------------------------------------+
+|"standard unit"    |           A number                |  The attribute standard unit             |
++-------------------+-----------------------------------+------------------------------------------+
+| "display unit"    |            A string               |   The attribute display unit             |
++-------------------+-----------------------------------+------------------------------------------+
+|    "format"       |            A string               | The attribute display format             |
++-------------------+-----------------------------------+------------------------------------------+
+|  "max value"      |          A number                 |   The attribute max value                |
++-------------------+-----------------------------------+------------------------------------------+
+|   "min value"     |           A number                |    The attribute min value               |
++-------------------+-----------------------------------+------------------------------------------+
+|  "max alarm"      |           A number                |    The attribute max alarm               |
++-------------------+-----------------------------------+------------------------------------------+
+|  "min alarm"      |           A number                |    The attribute min alarm               |
++-------------------+-----------------------------------+------------------------------------------+
+| "min warning"     |           A number                |  The attribute min warning               |
++-------------------+-----------------------------------+------------------------------------------+
+|"max warning"      |           A number                |  The attribute max warning               |
++-------------------+-----------------------------------+------------------------------------------+
+|  "delta time"     |           A number                | The attribute RDS alarm delta time       |
++-------------------+-----------------------------------+------------------------------------------+
+|   "delta val"     |           A number                | The attribute RDS alarm delta val        |
++-------------------+-----------------------------------+------------------------------------------+
+
+The PyDsExp class in Python
+---------------------------
+
+The rule of this class is to implement methods executed by commands and attributes.
+In our example, the code of this class looks like::
+
+    class PyDsExp(PyTango.Device_4Impl):
+
+        def __init__(self,cl,name):
+            PyTango.Device_4Impl.__init__(self, cl, name)
+            self.info_stream('In PyDsExp.__init__')
+            PyDsExp.init_device(self)
+
+        def init_device(self):
+            self.info_stream('In Python init_device method')
+            self.set_state(PyTango.DevState.ON)
+            self.attr_short_rw = 66
+            self.attr_long = 1246
+
+        #------------------------------------------------------------------
+
+        def delete_device(self):
+            self.info_stream('PyDsExp.delete_device')
+
+        #------------------------------------------------------------------
+        # COMMANDS
+        #------------------------------------------------------------------
+
+        def is_IOLong_allowed(self):
+            return self.get_state() == PyTango.DevState.ON
+
+        def IOLong(self, in_data):
+            self.info_stream('IOLong', in_data)
+            in_data = in_data * 2
+            self.info_stream('IOLong returns', in_data)
+            return in_data
+
+        #------------------------------------------------------------------
+
+        def is_IOStringArray_allowed(self):
+            return self.get_state() == PyTango.DevState.ON
+
+        def IOStringArray(self, in_data):
+            l = range(len(in_data)-1, -1, -1)
+            out_index=0
+            out_data=[]
+            for i in l:
+                self.info_stream('IOStringArray <-', in_data[out_index])
+                out_data.append(in_data[i])
+                self.info_stream('IOStringArray ->',out_data[out_index])
+                out_index += 1
+            self.y = out_data
+            return out_data
+
+        #------------------------------------------------------------------
+        # ATTRIBUTES
+        #------------------------------------------------------------------
+
+        def read_attr_hardware(self, data):
+            self.info_stream('In read_attr_hardware')
+
+        #------------------------------------------------------------------
+
+        def read_Long_attr(self, the_att):
+            self.info_stream("read_Long_attr")
+
+            the_att.set_value(self.attr_long)
+
+        #------------------------------------------------------------------
+
+        def read_Short_attr_rw(self, the_att):
+            self.info_stream("read_Short_attr_rw")
+
+            the_att.set_value(self.attr_short_rw)
+
+        #------------------------------------------------------------------
+
+        def write_Short_attr_rw(self, the_att):
+            self.info_stream("write_Short_attr_rw")
+
+            self.attr_short_rw = the_att.get_write_value()
+
+**Line 1**
+    The PyDsExp class has to inherit from the PyTango.Device_4Impl
+**Line 3 to 6**
+    PyDsExp class constructor. Note that at line 6, it calls the *init_device()* 
+    method
+**Line 8 to 12**
+    The init_device() method. It sets the device state (line 9) and initialises 
+    some data members
+**Line 16 to 17**
+    The delete_device() method. This method is not mandatory. You define it 
+    only if you have to do something specific before the device is destroyed
+**Line 23 to 30**
+    The two methods for the IOLong command. The first method is called 
+    *is_IOLong_allowed()* and it is the command is_allowed method (line 23 to 24). 
+    The second method has the same name than the command name. It is the method 
+    which executes the command. The command input data type is a Tango long
+    and therefore, this method receives a Python integer.
+**Line 34 to 47**
+    The two methods for the IOStringArray command. The first method is its 
+    is_allowed method (Line 34 to 35). The second one is the command 
+    execution method (Line 37 to 47). The command input data type is a String 
+    array. Therefore, the method receives the array in a Python list of Python
+    strings.
+**Line 53 to 54**
+    The *read_attr_hardware()* method. Its argument is a Python sequence of 
+    Python integer.
+**Line 58 to 61**
+    The method executed when the Long_attr attribute is read. Note that before
+    PyTango 7 it sets the attribute value with the PyTango.set_attribute_value
+    function. Now the same can be done using the set_value of the attribute
+    object
+**Line 65 to 68**
+    The method executed when the Short_attr_rw attribute is read.
+**Line 72 to 75**
+    The method executed when the Short_attr_rw attribute is written. 
+    Note that before PyTango 7 it gets the attribute value with a call to the 
+    Attribute method *get_write_value* with a list as argument. Now the write 
+    value can be obtained as the return value of the *get_write_value* call. And
+    in case it is a scalar there is no more the need to extract it from the list.
+
+General methods
+###############
+
+The following array summarizes how the general methods we have in a Tango 
+device server are implemented in Python.
+
++----------------------+-------------------------+-------------+-----------+
+|         Name         | Input par (with "self") |return value | mandatory |
++======================+=========================+=============+===========+
+|      init_device     |        None             |   None      |  Yes      |
++----------------------+-------------------------+-------------+-----------+
+|     delete_device    |        None             |   None      |  No       |
++----------------------+-------------------------+-------------+-----------+
+| always_executed_hook |        None             |   None      |  No       |
++----------------------+-------------------------+-------------+-----------+
+|    signal_handler    |   Python integer        |   None      |  No       |
++----------------------+-------------------------+-------------+-----------+
+| read_attr_hardware   | Python list of integer  |   None      |  No       |
++----------------------+-------------------------+-------------+-----------+
+
+Implementing a command
+######################
+
+Commands are defined as described above. Nevertheless, some methods implementing 
+them have to be written. These methods names are fixed and depend on command 
+name. They have to be called:
+
+    ``is_<Cmd_name>_allowed`` and ``<Cmd_name>``
+
+For instance, with a command called MyCmd, its is_allowed method has to be 
+called is_MyCmd_allowed and its execution method has to be called simply MyCmd. 
+The following array gives some more info on these methods.
+
++-----------------------+-------------------------+--------------------+-----------+
+|        Name           | Input par (with "self") | return value       | mandatory |
++=======================+=========================+====================+===========+
+| is_<Cmd_name>_allowed |        None             | Python boolean     |  No       |
++-----------------------+-------------------------+--------------------+-----------+
+|      Cmd_name         | Depends on cmd type     |Depends on cmd type |  Yes      |
++-----------------------+-------------------------+--------------------+-----------+
+
+Tango has more data types than Python which is more dynamic. The input and
+output values of the commands are translated according to the array below.
+Not that if PyTango is compiled with numpy support the numpy type will be
+the used for the input arguments. Also, it is recomended to use numpy arrays
+of the appropiate type for output arguments as well, as it is much more efficient.
+
++-------------------------+-------------------------------------------+
+|   Tango data type       |              Python type                  |
++=========================+===========================================+
+|          DEV_VOID       |                    No data                |
++-------------------------+-------------------------------------------+
+|       DEV_BOOLEAN       | bool                                      |
++-------------------------+-------------------------------------------+
+|         DEV_SHORT       | int                                       |
++-------------------------+-------------------------------------------+
+|         DEV_LONG        | int                                       |
++-------------------------+-------------------------------------------+
+|        DEV_LONG64       | long (on a 32 bits computer) or           |
+|                         | int (on a 64 bits computer)               |
++-------------------------+-------------------------------------------+
+|         DEV_FLOAT       | float                                     |
++-------------------------+-------------------------------------------+
+|       DEV_DOUBLE        | float                                     |
++-------------------------+-------------------------------------------+
+|        DEV_USHORT       | int                                       |
++-------------------------+-------------------------------------------+
+|        DEV_ULONG        | int                                       |
++-------------------------+-------------------------------------------+
+|        DEV_ULONG64      | long (on a 32 bits computer) or           |
+|                         | int (on a 64 bits computer)               |
++-------------------------+-------------------------------------------+
+|        DEV_STRING       | str                                       |
++-------------------------+-------------------------------------------+
+|    DEVVAR_CHARARRAY     | numpy.ndarray(dtype=numpy.uint8) or       |
+|                         | sequence<int>                             |
++-------------------------+-------------------------------------------+
+|    DEVVAR_SHORTARRAY    | numpy.ndarray(dtype=numpy.int16) or       |
+|                         | sequence<int>                             |
++-------------------------+-------------------------------------------+
+|    DEVVAR_LONGARRAY     | numpy.ndarray(dtype=numpy.int32) or       |
+|                         | sequence<int>                             |
++-------------------------+-------------------------------------------+
+|   DEVVAR_LONG64ARRAY    | numpy.ndarray(dtype=numpy.int64) or       |
+|                         | sequence<long> (on a 32 bits computer) or |
+|                         | sequence<int> (on a 64 bits computer)     |
++-------------------------+-------------------------------------------+
+|    DEVVAR_FLOATARRAY    | numpy.ndarray(dtype=numpy.float32) or     |
+|                         | sequence<float>                           |
++-------------------------+-------------------------------------------+
+|   DEVVAR_DOUBLEARRAY    | numpy.ndarray(dtype=numpy.float64) or     |
+|                         | sequence<float>                           |
++-------------------------+-------------------------------------------+
+|   DEVVAR_USHORTARRAY    | numpy.ndarray(dtype=numpy.uint16) or      |
+|                         | sequence<int>                             |
++-------------------------+-------------------------------------------+
+|   DEVVAR_ULONGARRAY     | numpy.ndarray(dtype=numpy.uint32) or      |
+|                         | sequence<int>                             |
++-------------------------+-------------------------------------------+
+|  DEVVAR_ULONG64ARRAY    | numpy.ndarray(dtype=numpy.uint64) or      |
+|                         | sequence<long> (on a 32 bits computer) or |
+|                         | sequence<int> (on a 64 bits computer)     |
++-------------------------+-------------------------------------------+
+|   DEVVAR_STRINGARRAY    | sequence<str>                             |
++-------------------------+-------------------------------------------+
+|                         | A sequence with two elements:             |
+| DEVVAR_LONGSTRINGARRAY  |  1. numpy.ndarray(dtype=numpy.int32) or   |
+|                         |     sequence<int>                         |
+|                         |  2. sequence<str>                         |
++-------------------------+-------------------------------------------+
+|                         | A sequence with two elements:             |
+|DEVVAR_DOUBLESTRINGARRAY |  1. numpy.ndarray(dtype=numpy.float64) or |
+|                         |     sequence<float>                       |
+|                         |  2. sequence<str>                         |
++-------------------------+-------------------------------------------+
+
+The following code is an example of how you write code executed when a client
+calls a command named IOLong::
+
+    def is_IOLong_allowed(self):
+        self.debug_stream("in is_IOLong_allowed")
+        return self.get_state() == PyTango.DevState.ON
+
+    def IOLong(self, in_data):
+        self.info_stream('IOLong', in_data)
+        in_data = in_data * 2
+        self.info_stream('IOLong returns', in_data)
+        return in_data
+
+**Line 1-3**
+    the is_IOLong_allowed method determines in which conditions the command
+    'IOLong' can be executed. In this case, the command can only be executed if
+    the device is in 'ON' state.
+**Line 6**
+    write a log message to the tango INFO stream (click :ref:`here <logging>` for
+    more information about PyTango log system).
+**Line 7**
+    does something with the input parameter
+**Line 8**
+    write another log message to the tango INFO stream (click :ref:`here <logging>` for
+    more information about PyTango log system).
+**Line 9**
+    return the output of executing the tango command
+    
+Implementing an attribute
+#########################
+
+Attributes are defined as described in chapter 5.3.2. Nevertheless, some methods
+implementing them have to be written. These methods names are fixed and depend 
+on attribute name. They have to be called:
+
+    ``is_<Attr_name>_allowed`` and ``read_<Attr_name>`` or/and ``write_<Attr_name>``
+
+For instance, with an attribute called MyAttr, its is_allowed method has to be 
+called is_MyAttr_allowed, its read method has to be called read_MyAttr and 
+its write method has to be called write_MyAttr. The following array gives some 
+more info on these methods.
+
++-------------+-------------+-------------------------------------------+
+| data format | data type   |  python type                              |
++=============+=============+===========================================+
+| SCALAR      | DEV_BOOLEAN | bool                                      |
+|             +-------------+-------------------------------------------+
+|             | DEV_UCHAR   | int                                       |
+|             +-------------+-------------------------------------------+
+|             | DEV_SHORT   | int                                       |
+|             +-------------+-------------------------------------------+
+|             | DEV_USHORT  | int                                       |
+|             +-------------+-------------------------------------------+
+|             | DEV_LONG    | int                                       |
+|             +-------------+-------------------------------------------+
+|             | DEV_ULONG   | int                                       |
+|             +-------------+-------------------------------------------+
+|             | DEV_LONG64  | int/long                                  |
+|             +-------------+-------------------------------------------+
+|             | DEV_ULONG64 | int/long                                  |
+|             +-------------+-------------------------------------------+
+|             | DEV_FLOAT   | float                                     |
+|             +-------------+-------------------------------------------+
+|             | DEV_DOUBLE  | float                                     |
+|             +-------------+-------------------------------------------+
+|             | DEV_STRING  | str                                       |
++-------------+-------------+-------------------------------------------+
+| SPECTRUM    | DEV_BOOLEAN | numpy.ndarray(dtype=numpy.bool) or        |
+| or          |             | sequence<bool>                            |
+| IMAGE       +-------------+-------------------------------------------+
+|             | DEV_UCHAR   | numpy.ndarray(dtype=numpy.uint8) or       |
+|             |             | sequence<int>                             |
+|             +-------------+-------------------------------------------+
+|             | DEV_SHORT   | numpy.ndarray(dtype=numpy.int16) or       |
+|             |             | sequence<int>                             |
+|             +-------------+-------------------------------------------+
+|             | DEV_USHORT  | numpy.ndarray(dtype=numpy.uint16) or      |
+|             |             | sequence<int>                             |
+|             +-------------+-------------------------------------------+
+|             | DEV_LONG    | numpy.ndarray(dtype=numpy.int32) or       |
+|             |             | sequence<int>                             |
+|             +-------------+-------------------------------------------+
+|             | DEV_ULONG   | numpy.ndarray(dtype=numpy.uint32) or      |
+|             |             | sequence<int>                             |
+|             +-------------+-------------------------------------------+
+|             | DEV_LONG64  | numpy.ndarray(dtype=numpy.int64) or       |
+|             |             | sequence<int>                             |
+|             +-------------+-------------------------------------------+
+|             | DEV_ULONG64 | numpy.ndarray(dtype=numpy.uint64) or      |
+|             |             | sequence<int>                             |
+|             +-------------+-------------------------------------------+
+|             | DEV_FLOAT   | numpy.ndarray(dtype=numpy.float32) or     |
+|             |             | sequence<float>                           |
+|             +-------------+-------------------------------------------+
+|             | DEV_DOUBLE  | numpy.ndarray(dtype=numpy.float64) or     |
+|             |             | sequence<float>                           |
+|             +-------------+-------------------------------------------+
+|             | DEV_STRING  | sequence<str>                             |
++-------------+-------------+-------------------------------------------+
+
+For SPECTRUM and IMAGES the actual sequence object used depends on the context 
+where the tango data is used, and the availability of ``numpy``.
+
+1. for properties the sequence is always a ``list``
+    Example:
+    
+    >>> import PyTango
+    >>> db = PyTango.Database()
+    >>> s = db.get_property(["TangoSynchrotrons"])
+    >>> print type(s)
+    <type 'list'>
+
+2. for attribute/command values
+    - ``numpy.ndarray`` if PyTango was compiled with numpy support (default) and ``numpy`` is installed.
+    - ``list`` otherwise
+    
+The following code is an example of how you write code executed when a client read an attribute which is
+called Long_attr::
+    
+    def read_Long_attr(self, the_att):
+        self.info_stream("read attribute name Long_attr")
+        the_att.set_value(self.attr_long)
+
+**Line 1**
+    Method declaration with "the_att" being an instance of the Attribute
+    class representing the Long_attr attribute
+**Line 2**
+    write a log message to the tango INFO stream (click :ref:`here <logging>` for
+    more information about PyTango log system).
+**Line 3**
+    Set the attribute value using the method set_value() with the attribute 
+    value as parameter.
+    
+The following code is an example of how you write code executed when a client 
+write the Short_attr_rw attribute::
+
+    def write_Short_attr_rw(self,the_att):
+        self.info_stream("In write_Short_attr_rw for attribute ",the_att.get_name())
+        self.attr_short_rw = the_att.get_write_value(data)
+
+**Line 1**
+       Method declaration with "the_att" being an instance of the Attribute 
+       class representing the Short_attr_rw attribute
+**Line 2**
+    write a log message to the tango INFO stream (click :ref:`here <logging>` for
+    more information about PyTango log system).
+**Line 3**
+    Get the value sent by the client using the method get_write_value() and
+    store the value written in the device object. Our attribute is a scalar 
+    short attribute so the return value is an int
+
+.. _logging:
+
+Logging
+#######
+
+This chapter instructs you on how to use the tango logging API (log4tango) to
+create tango log messages on your device server.
+
+The logging system explained here is the Tango Logging Service (TLS). For
+detailed information on how this logging system works please check:
+
+    * `3.5 The tango logging service <http://www.esrf.eu/computing/cs/tango/tango_doc/kernel_doc/ds_prog/node4.html#sec:The-Tango-Logging>`_
+    * `9.3 The tango logging service <http://www.esrf.eu/computing/cs/tango/tango_doc/kernel_doc/ds_prog/node9.html#SECTION00930000000000000000>`_
+
+The easiest way to start seeing log messages on your device server console is
+by starting it with the verbose option. Example::
+
+    python PyDsExp.py PyDs1 -v4
+
+This activates the console tango logging target and filters messages with 
+importance level DEBUG or more.
+The links above provided detailed information on how to configure log levels 
+and log targets. In this document we will focus on how to write log messages on
+your device server.
+
+Basic logging
+~~~~~~~~~~~~~
+
+The most basic way to write a log message on your device is to use the
+:class:`PyTango.DeviceImpl` logging related methods:
+
+    * :meth:`PyTango.DeviceImpl.debug_stream`
+    * :meth:`PyTango.DeviceImpl.info_stream`
+    * :meth:`PyTango.DeviceImpl.warn_stream`
+    * :meth:`PyTango.DeviceImpl.error_stream`
+    * :meth:`PyTango.DeviceImpl.fatal_stream`
+
+Example::
+
+    def read_Long_attr(self, the_att):
+        self.info_stream("read attribute name Long_attr")
+        the_att.set_value(self.attr_long)
+
+This will print a message like::
+
+    1282206864 [-1215867200] INFO test/pydsexp/1 read attribute name Long_attr
+
+every time a client asks to read the 'Long_attr' attribute value.
+
+Logging with print statement
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+*This feature is only possible since PyTango 7.1.3*
+
+It is possible to use the print statement to log messages into the tango logging
+system. This is achieved by using the python's print extend form sometimes
+refered to as *print chevron*.
+
+Same example as above, but now using *print chevron*::
+
+    def read_Long_attr(self, the_att):
+        print >>self.log_info, "read attribute name Long_attr"
+        the_att.set_value(self.attr_long)
+
+Or using the python 3k print function::
+
+    def read_Long_attr(self, the_att):
+        print("read attribute name Long_attr", file=self.log_info)
+        the_att.set_value(self.attr_long)
+
+Logging with decorators
+~~~~~~~~~~~~~~~~~~~~~~~
+
+*This feature is only possible since PyTango 7.1.3*
+
+PyTango provides a set of decorators that place automatic log messages when
+you enter and when you leave a python method. For example::
+
+    @PyTango.DebugIt()
+    def read_Long_attr(self, the_att):
+        the_att.set_value(self.attr_long)
+
+will generate a pair of log messages each time a client asks for the 'Long_attr'
+value. Your output would look something like::
+
+    1282208997 [-1215965504] DEBUG test/pydsexp/1 -> read_Long_attr()
+    1282208997 [-1215965504] DEBUG test/pydsexp/1 <- read_Long_attr()
+
+Decorators exist for all tango log levels:
+    * :class:`PyTango.DebugIt`
+    * :class:`PyTango.InfoIt`
+    * :class:`PyTango.WarnIt`
+    * :class:`PyTango.ErrorIt`
+    * :class:`PyTango.FatalIt`
+
+The decorators receive three optional arguments:
+    * show_args - shows method arguments in log message (defaults to False)
+    * show_kwargs shows keyword method arguments in log message (defaults to False)
+    * show_ret - shows return value in log message (defaults to False)
+
+Example::
+    
+    @PyTango.DebugIt(show_args=True, show_ret=True)
+    def IOLong(self, in_data):
+        return in_data * 2
+
+will output something like::
+
+    1282221947 [-1261438096] DEBUG test/pydsexp/1 -> IOLong(23)
+    1282221947 [-1261438096] DEBUG test/pydsexp/1 46 <- IOLong()
+
+Dynamic devices
+###############
+
+*This feature is only possible since PyTango 7.1.2*
+
+Starting from PyTango 7.1.2 it is possible to create devices in a device server
+"en caliente". This means that you can create a command in your "management device"
+of a device server that creates devices of (possibly) several other tango classes.
+There are two ways to create a new device which are described below.
+
+Dynamic device from a known tango class name
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you know the tango class name but you don't have access to the :class:`PyTango.DeviceClass`
+(or you are too lazy to search how to get it ;-) the way to do it is call 
+:meth:`PyTango.Util.create_device` / :meth:`PyTango.Util.delete_device`.
+Here is an example of implementing a tango command on one of your devices that 
+creates a device of some arbitrary class (the example assumes the tango commands
+'CreateDevice' and 'DeleteDevice' receive a parameter of type DevVarStringArray
+with two strings. No error processing was done on the code for simplicity sake)::
+
+    class MyDevice(PyTango.Device_4Impl):
+        ...
+        
+        def CreateDevice(self, pars):
+            klass_name, dev_name = pars
+            util = PyTango.Util.instance()
+            util.create_device(klass_name, dev_name, alias=None, cb=None)
+        
+        def DeleteDevice(self, pars):
+            klass_name, dev_name = pars
+            util = PyTango.Util.instance()
+            util.delete_device(klass_name, dev_name)
+
+An optional callback can be registered that will be executed after the device is
+registed in the tango database but before the actual device object is created and its
+init_device method is called. You can, for example, initialize some device properties
+here.
+
+Dynamic device from a known tango class
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you already have access to the :class:`PyTango.DeviceClass` object that
+corresponds to the tango class of the device to be created you can call directly
+the :meth:`PyTango.DeviceClass.create_device` / :meth:`PyTango.DeviceClass.delete_device`.
+For example, if you wish to create a clone of your device, you can create a 
+tango command called Clone::
+
+    class MyDevice(PyTango.Device_4Impl):
+        ...
+        
+        def fill_new_device_properties(self, dev_name):
+            prop_names = db.get_device_property_list(self.get_name(), "*")
+            prop_values = db.get_device_property(self.get_name(), prop_names.value_string)
+            db.put_device_property(dev_name, prop_values)
+            
+            # do the same for attributes...
+            ... 
+        
+        def Clone(self, dev_name):
+            klass = self.get_device_class()
+            klass.create_device(dev_name, alias=None, cb=self.fill_new_device_properties)
+            
+        def DeleteSibling(self, dev_name):
+            klass = self.get_device_class()
+            klass.delete_device(dev_name)
+            
+Note that the cb parameter is optional. In the example it is given for demonstration purposes only.
+
+Dynamic attributes
+##################
+
+It is also possible to create dynamic attributes within a Python device server. 
+There are several ways to create dynamic attributes. One of the way, is to 
+create all the devices within a loop, then to create the dynamic attributes and
+finally to make all the devices available for the external world. In C++ device
+server, this is typically done within the <Device>Class::device_factory() method.
+In Python device server, this method is generic and the user does not have one.
+Nevertheless, this generic device_factory method calls a method named dyn_attr()
+allowing the user to create his dynamic attributes. It is simply necessary to
+re-define this method within your <Device>Class and to create the dynamic 
+attribute within this method:
+
+    ``dyn_attr(self, dev_list)``
+    
+    where dev_list is a list containing all the devices created by the 
+    generic device_factory() method.
+
+There is another point to be noted regarding dynamic attribute within Python 
+device server. The Tango Python device server core checks that for each 
+attribute it exists methods named <attribute_name>_read and/or <attribute_name>_write and/or 
+is_<attribute_name>_allowed. Using dynamic attribute, it is not possible to 
+define these methods because attributes name and number are known only at run-time. 
+To address this issue, the Device_3Impl::add_attribute() method has a diferent
+signature for Python device server which is:
+
+    ``add_attribute(self, attr, r_meth = None, w_meth = None, is_allo_meth = None)``
+    
+    attr is an instance of the Attr class, r_meth is the method which has to be 
+    executed with the attribute is read, w_meth is the method to be executed 
+    when the attribute is written and is_allo_meth is the method to be executed
+    to implement the attribute state machine. The method passed here as argument
+    as to be class method and not object method. Which argument you have to use 
+    depends on the type of the attribute (A WRITE attribute does not need a 
+    read method). Note, that depending on the number of argument you pass to this
+    method, you may have to use Python keyword argument. The necessary methods 
+    required by the Tango Python device server core will be created automatically
+    as a forward to the methods given as arguments.
+
+Mixing Tango classes (Python and C++) in a Python Tango device server
+---------------------------------------------------------------------
+
+Within the same python interpreter, it is possible to mix several Tango classes. 
+Here is an example of the main function of a device server with two Tango classes
+called IRMiror and PLC::
+
+    import PyTango
+    import sys
+
+    if __name__ == '__main__':
+        util = PyTango.Util(sys.argv)
+        # Deprecated: util.add_TgClass(PLCClass, PLC, 'PLC')
+        # Deprecated: util.add_TgClass(IRMirrorClass, IRMirror, 'IRMirror')
+        util.add_class(PLCClass, PLC, 'PLC')
+        util.add_class(IRMirrorClass, IRMirror, 'IRMirror')
+        
+        U = PyTango.Util.instance()
+        U.server_init()
+        U.server_run()
+
+:Line 6: The Tango class PLC is registered in the device server
+:Line 7: The Tango class IRMirror is registered in the device server
+
+It is also possible to add C++ Tango class in a Python device server as soon as:
+    1. The Tango class is in a shared library
+    2. It exist a C function to create the Tango class
+
+For a Tango class called MyTgClass, the shared library has to be called 
+MyTgClass.so and has to be in a directory listed in the LD_LIBRARY_PATH 
+environment variable. The C function creating the Tango class has to be called 
+_create_MyTgClass_class() and has to take one parameter of type "char \*" which 
+is the Tango class name. Here is an example of the main function of the same 
+device server than before but with one C++ Tango class called SerialLine::
+
+    import PyTango
+    import sys
+    
+    if __name__ == '__main__':
+        py = PyTango.Util(sys.argv)
+        # Deprecated: py.add_Cpp_TgClass('SerialLine', 'SerialLine')
+        # Deprecated: py.add_TgClass(PLCClass, PLC, 'PLC')
+        # Deprecated: py.add_TgClass(IRMirrorClass, IRMirror, 'IRMirror')
+        util.add_class('SerialLine', 'SerialLine', language="c++")
+        util.add_class(PLCClass, PLC, 'PLC')
+        util.add_class(IRMirrorClass, IRMirror, 'IRMirror')
+        
+        U = PyTango.Util.instance()
+        U.server_init()
+        U.server_run()
+
+:Line 6: The C++ class is registered in the device server
+:Line 8 and 9: The two Python classes are registered in the device server
+
+Server API
+----------
+
+.. toctree::
+    :maxdepth: 2
+
+    device
+    device_class
+    logging
+    attribute
+    util
diff --git a/doc/server/logging.rst b/doc/server/logging.rst
new file mode 100644
index 0000000..704b953
--- /dev/null
+++ b/doc/server/logging.rst
@@ -0,0 +1,40 @@
+Logging decorators
+==================
+
+.. currentmodule:: PyTango
+
+LogIt
+-----
+
+.. autoclass:: PyTango.LogIt
+    :members:
+
+DebugIt
+-------
+
+.. autoclass:: PyTango.DebugIt
+    :members:
+
+InfoIt
+------
+
+.. autoclass:: PyTango.InfoIt
+    :members:
+
+WarnIt
+-------
+
+.. autoclass:: PyTango.WarnIt
+    :members:
+
+ErrorIt
+-------
+
+.. autoclass:: PyTango.ErrorIt
+    :members:
+
+FatalIt
+-------
+
+.. autoclass:: PyTango.FatalIt
+    :members:
diff --git a/doc/server/util.rst b/doc/server/util.rst
new file mode 100644
index 0000000..7641f66
--- /dev/null
+++ b/doc/server/util.rst
@@ -0,0 +1,8 @@
+Util
+====
+
+.. currentmodule:: PyTango
+
+.. autoclass:: PyTango.Util
+    :members:
+    :inherited-members:
diff --git a/doc/sphinxext/ipython_console_highlighting.py b/doc/sphinxext/ipython_console_highlighting.py
new file mode 100644
index 0000000..9a2e54f
--- /dev/null
+++ b/doc/sphinxext/ipython_console_highlighting.py
@@ -0,0 +1,114 @@
+"""reST directive for syntax-highlighting ipython interactive sessions.
+
+XXX - See what improvements can be made based on the new (as of Sept 2009)
+'pycon' lexer for the python console.  At the very least it will give better
+highlighted tracebacks.
+"""
+
+#-----------------------------------------------------------------------------
+# Needed modules
+
+# Standard library
+import re
+
+# Third party
+from pygments.lexer import Lexer, do_insertions
+from pygments.lexers.agile import (PythonConsoleLexer, PythonLexer, 
+                                   PythonTracebackLexer)
+from pygments.token import Comment, Generic
+
+from sphinx import highlighting
+
+#-----------------------------------------------------------------------------
+# Global constants
+line_re = re.compile('.*?\n')
+
+#-----------------------------------------------------------------------------
+# Code begins - classes and functions
+
+class IPythonConsoleLexer(Lexer):
+    """
+    For IPython console output or doctests, such as:
+
+    .. sourcecode:: ipython
+
+      In [1]: a = 'foo'
+
+      In [2]: a
+      Out[2]: 'foo'
+
+      In [3]: print a
+      foo
+
+      In [4]: 1 / 0
+
+    Notes:
+
+      - Tracebacks are not currently supported.
+
+      - It assumes the default IPython prompts, not customized ones.
+    """
+    
+    name = 'IPython console session'
+    aliases = ['ipython']
+    mimetypes = ['text/x-ipython-console']
+    input_prompt = re.compile("(In \[(?P<N>[0-9]+)\]: )|(   \.\.\.+:)")
+    output_prompt = re.compile("(Out\[(?P<N>[0-9]+)\]: )|(   \.\.\.+:)")
+    continue_prompt = re.compile("   \.\.\.+:")
+    tb_start = re.compile("\-+")
+
+    def get_tokens_unprocessed(self, text):
+        pylexer = PythonLexer(**self.options)
+        tblexer = PythonTracebackLexer(**self.options)
+
+        curcode = ''
+        insertions = []
+        for match in line_re.finditer(text):
+            line = match.group()
+            input_prompt = self.input_prompt.match(line)
+            continue_prompt = self.continue_prompt.match(line.rstrip())
+            output_prompt = self.output_prompt.match(line)
+            if line.startswith("#"):
+                insertions.append((len(curcode),
+                                   [(0, Comment, line)]))
+            elif input_prompt is not None:
+                insertions.append((len(curcode),
+                                   [(0, Generic.Prompt, input_prompt.group())]))
+                curcode += line[input_prompt.end():]
+            elif continue_prompt is not None:
+                insertions.append((len(curcode),
+                                   [(0, Generic.Prompt, continue_prompt.group())]))
+                curcode += line[continue_prompt.end():]
+            elif output_prompt is not None:
+                # Use the 'error' token for output.  We should probably make
+                # our own token, but error is typicaly in a bright color like
+                # red, so it works fine for our output prompts.
+                insertions.append((len(curcode),
+                                   [(0, Generic.Error, output_prompt.group())]))
+                curcode += line[output_prompt.end():]
+            else:
+                if curcode:
+                    for item in do_insertions(insertions,
+                                              pylexer.get_tokens_unprocessed(curcode)):
+                        yield item
+                        curcode = ''
+                        insertions = []
+                yield match.start(), Generic.Output, line
+        if curcode:
+            for item in do_insertions(insertions,
+                                      pylexer.get_tokens_unprocessed(curcode)):
+                yield item
+
+
+def setup(app):
+    """Setup as a sphinx extension."""
+
+    # This is only a lexer, so adding it below to pygments appears sufficient.
+    # But if somebody knows that the right API usage should be to do that via
+    # sphinx, by all means fix it here.  At least having this setup.py
+    # suppresses the sphinx warning we'd get without it.
+    pass
+
+#-----------------------------------------------------------------------------
+# Register the extension as a valid pygments lexer
+highlighting.lexers['ipython'] = IPythonConsoleLexer()
\ No newline at end of file
diff --git a/doc/sphinxext/spock_console_highlighting.py b/doc/sphinxext/spock_console_highlighting.py
new file mode 100644
index 0000000..c95f048
--- /dev/null
+++ b/doc/sphinxext/spock_console_highlighting.py
@@ -0,0 +1,116 @@
+"""reST directive for syntax-highlighting spock interactive sessions.
+"""
+
+#-----------------------------------------------------------------------------
+# Needed modules
+
+# Standard library
+import re
+import copy
+
+# Third party
+from pygments.lexer import Lexer, do_insertions
+from pygments.lexers.agile import (PythonConsoleLexer, PythonLexer, 
+                                   PythonTracebackLexer)
+from pygments.token import Comment, Generic
+from pygments.style import Style
+import pygments.styles
+from sphinx import highlighting
+
+#-----------------------------------------------------------------------------
+# Global constants
+line_re = re.compile('.*?\n')
+
+DftStyle = pygments.styles.get_style_by_name("default")
+
+class SpockStyle(DftStyle):
+    
+    styles = copy.copy(DftStyle.styles)
+    styles[Generic.Prompt] = 'bold #800080'
+
+class SpockConsoleLexer(Lexer):
+    """
+    For spock console output or doctests, such as:
+
+    .. sourcecode:: spock
+
+      Spock <homer:10000> [1]: a = 'foo'
+
+      Spock <homer:10000> [2]: a
+                   Result [2]: 'foo'
+
+      Spock <homer:10000> [3]: print a
+      foo
+
+      Spock <homer:10000> [4]: 1 / 0
+
+    Notes:
+
+      - Tracebacks are not currently supported.
+
+      - It assumes the default spock prompts, not customized ones.
+    """
+    
+    name = 'Spock console session'
+    aliases = ['spock']
+    mimetypes = ['text/x-spock-console']
+    input_prompt = re.compile("(Spock \<\w+:\d+\> \[(?P<N>[0-9]+)\]: )|(   \.\.\.+:)")
+    output_prompt = re.compile("(\s*Result \[(?P<N>[0-9]+)\]: )|(   \.\.\.+:)")
+    continue_prompt = re.compile("   \.\.\.+:")
+    tb_start = re.compile("\-+")
+
+    def get_tokens_unprocessed(self, text):
+        pylexer = PythonLexer(**self.options)
+        tblexer = PythonTracebackLexer(**self.options)
+
+        curcode = ''
+        insertions = []
+        for match in line_re.finditer(text):
+            line = match.group()
+            input_prompt = self.input_prompt.match(line)
+            continue_prompt = self.continue_prompt.match(line.rstrip())
+            output_prompt = self.output_prompt.match(line)
+            if line.startswith("#"):
+                insertions.append((len(curcode),
+                                   [(0, Comment, line)]))
+            elif input_prompt is not None:
+                insertions.append((len(curcode),
+                                   [(0, Generic.Prompt, input_prompt.group())]))
+                curcode += line[input_prompt.end():]
+            elif continue_prompt is not None:
+                insertions.append((len(curcode),
+                                   [(0, Generic.Prompt, continue_prompt.group())]))
+                curcode += line[continue_prompt.end():]
+            elif output_prompt is not None:
+                # Use the 'error' token for output.  We should probably make
+                # our own token, but error is typicaly in a bright color like
+                # red, so it works fine for our output prompts.
+                insertions.append((len(curcode),
+                                   [(0, Generic.Error, output_prompt.group())]))
+                curcode += line[output_prompt.end():]
+            else:
+                if curcode:
+                    for item in do_insertions(insertions,
+                                              pylexer.get_tokens_unprocessed(curcode)):
+                        yield item
+                        curcode = ''
+                        insertions = []
+                yield match.start(), Generic.Output, line
+        if curcode:
+            for item in do_insertions(insertions,
+                                      pylexer.get_tokens_unprocessed(curcode)):
+                yield item
+
+
+def setup(app):
+    """Setup as a sphinx extension."""
+
+    # This is only a lexer, so adding it below to pygments appears sufficient.
+    # But if somebody knows that the right API usage should be to do that via
+    # sphinx, by all means fix it here.  At least having this setup.py
+    # suppresses the sphinx warning we'd get without it.
+    pass
+
+#-----------------------------------------------------------------------------
+# Register the extension as a valid pygments lexer
+highlighting.lexers['spock'] = SpockConsoleLexer()
\ No newline at end of file
diff --git a/doc/spock/features.rst b/doc/spock/features.rst
new file mode 100644
index 0000000..d7b54c1
--- /dev/null
+++ b/doc/spock/features.rst
@@ -0,0 +1,40 @@
+
+.. _spock-features:
+
+Features
+========
+
+Spock works like a normal python console, but it gives you in addition a nice
+set of features from IPython_ like:
+
+    - proper (bash-like) command completion
+    - automatic expansion of python variables, functions, types
+    - command history (with up/down arrow keys, %hist command)
+    - help system ( object? syntax, help(object))
+    - persistently store your favorite variables
+    - color modes
+ 
+(for a complete list checkout the `IPython tutorial <http://ipython.scipy.org/doc/manual/html/interactive/tutorial.html>`_)
+
+Plus an additional set o Tango_ specific features:
+
+    - automatic import of Tango objects to the console namespace (PyTango module,
+      :class:`PyTango.DeviceProxy` (=Device), :class:`PyTango.Database`, :class:`PyTango.Group`
+      and :class:`PyTango.AttributeProxy` (=Attribute))
+    - device name completion
+    - attribute name completion
+    - automatic tango object member completion
+    - list tango devices, classes, servers
+    - customized tango error message
+    - tango error introspection
+    - switch database
+    - refresh database
+    - list tango devices, classes
+    - store favorite tango objects
+    - store favorite tango devices
+    - tango color modes
+
+Check the :ref:`spock-highlights` to see how to put these feature to good use :-)
+
+.. _IPython: http://ipython.scipy.org/
+.. _Tango: http://www.tango-controls.org/
\ No newline at end of file
diff --git a/doc/spock/highlights.rst b/doc/spock/highlights.rst
new file mode 100644
index 0000000..8ff98b7
--- /dev/null
+++ b/doc/spock/highlights.rst
@@ -0,0 +1,577 @@
+
+.. currentmodule:: PyTango
+
+.. _spock-highlights:
+
+Highlights
+==========
+
+Tab completion
+--------------
+
+Spock exports many tango specific objects to the console namespace.
+These include:
+
+    - the PyTango module itself
+      
+      .. sourcecode:: spock
+
+            Spock <homer:10000> [1]: PyTango
+                         Result [1]: <module 'PyTango' from ...>
+                         
+    - The :class:`DeviceProxy` (=Device), :class:`AttributeProxy` (=Attribute),
+      :class:`Database` and :class:`Group` classes
+      
+      .. sourcecode:: spock
+
+            Spock <homer:10000> [1]: De<tab>
+            DeprecationWarning            Device       DeviceProxy
+
+            Spock <homer:10000> [2]: Device
+                         Result [2]: <class 'PyTango._PyTango.DeviceProxy'>
+            
+            Spock <homer:10000> [3]: Device("sys/tg_test/1")
+                         Result [3]: DeviceProxy(sys/tg_test/1)
+                         
+            Spock <homer:10000> [4]: Datab<tab>
+            
+            Spock <homer:10000> [4]: Database
+            
+            Spock <homer:10000> [4]: Att<tab>
+            Attribute       AttributeError  AttributeProxy
+            
+    - The tango :class:`PyTango.Database` object to which the spock session is 
+      currently connected
+      
+      .. sourcecode:: spock
+
+            Spock <homer:10000> [1]: db
+                         Result [1]: Database(homer, 10000)
+    
+Device name completion
+----------------------
+
+Spock knows the complete list of device names (including alias) for the current
+tango database. This means that when you try to create a new Device, by pressing
+<tab> you can see a context sensitive list of devices.
+
+.. sourcecode:: spock
+
+    Spock <homer:10000> [1]: test = Device("<tab>
+    Display all 3654 possibilities? (y or n) n
+    
+    Spock <homer:10000> [1]: test = Device("sys<tab>
+    sys/access_control/1  sys/database/2        sys/tautest/1         sys/tg_test/1
+    
+    Spock <homer:10000> [2]: test = Device("sys/tg_test/1")
+
+Attribute name completion
+-------------------------
+
+Spock can inspect the list of attributes in case the device server for the device
+where the attribute resides is running.
+
+.. sourcecode:: spock
+
+    Spock <homer:10000> [1]: short_scalar = Attribute("sys<tab>
+    sys/access_control/1/  sys/database/2/        sys/tautest/1/         sys/tg_test/1/
+    
+    Spock <homer:10000> [1]: short_scalar = Attribute("sys/tg_test/1/<tab>
+    sys/tg_test/1/State                sys/tg_test/1/no_value
+    sys/tg_test/1/Status               sys/tg_test/1/short_image
+    sys/tg_test/1/ampli                sys/tg_test/1/short_image_ro
+    sys/tg_test/1/boolean_image        sys/tg_test/1/short_scalar
+    sys/tg_test/1/boolean_image_ro     sys/tg_test/1/short_scalar_ro
+    sys/tg_test/1/boolean_scalar       sys/tg_test/1/short_scalar_rww
+    sys/tg_test/1/boolean_spectrum     sys/tg_test/1/short_scalar_w
+    sys/tg_test/1/boolean_spectrum_ro  sys/tg_test/1/short_spectrum
+    sys/tg_test/1/double_image         sys/tg_test/1/short_spectrum_ro
+    sys/tg_test/1/double_image_ro      sys/tg_test/1/string_image
+    sys/tg_test/1/double_scalar        sys/tg_test/1/string_image_ro
+    ...
+
+    Spock <homer:10000> [1]: short_scalar = Attribute("sys/tg_test/1/shost_scalar")
+    
+    Spock <homer:10000> [29]: print test.read()
+    DeviceAttribute[
+    data_format = PyTango._PyTango.AttrDataFormat.SCALAR
+      dim_x = 1
+      dim_y = 0
+    has_failed = False
+    is_empty = False
+       name = 'short_scalar'
+    nb_read = 1
+    nb_written = 1
+    quality = PyTango._PyTango.AttrQuality.ATTR_VALID
+    r_dimension = AttributeDimension(dim_x = 1, dim_y = 0)
+       time = TimeVal(tv_nsec = 0, tv_sec = 1279723723, tv_usec = 905598)
+       type = PyTango._PyTango.CmdArgType.DevShort
+      value = 47
+    w_dim_x = 1
+    w_dim_y = 0
+    w_dimension = AttributeDimension(dim_x = 1, dim_y = 0)
+    w_value = 0]
+
+Automatic tango object member completion
+----------------------------------------
+
+When you create a new tango object, (ex.: a device), spock is able to find out
+dynamically which are the members of this device (including tango commands 
+and attributes if the device is currently running)
+
+.. sourcecode:: spock
+
+    Spock <homer:10000> [1]: test = Device("sys/tg_test/1")
+    
+    Spock <homer:10000> [2]: test.<tab>
+    Display all 240 possibilities? (y or n)
+    ...
+    test.DevVoid                            test.get_access_control
+    test.Init                               test.get_asynch_replies
+    test.State                              test.get_attribute_config
+    test.Status                             test.get_attribute_config_ex
+    test.SwitchStates                       test.get_attribute_list
+    ...
+    
+    Spock <homer:10000> [2]: test.short_<tab>
+    test.short_image        test.short_scalar       test.short_scalar_rww   test.short_spectrum
+    test.short_image_ro     test.short_scalar_ro    test.short_scalar_w     test.short_spectrum_ro
+
+    Spock <homer:10000> [2]: test.short_scalar        # old style: test.read_attribute("short_scalar").value
+                 Result [2]: 252
+
+    Spock <homer:10000> [3]: test.Dev<tab>
+    test.DevBoolean               test.DevUShort                test.DevVarShortArray
+    test.DevDouble                test.DevVarCharArray          test.DevVarStringArray
+    test.DevFloat                 test.DevVarDoubleArray        test.DevVarULongArray
+    test.DevLong                  test.DevVarDoubleStringArray  test.DevVarUShortArray
+    test.DevShort                 test.DevVarFloatArray         test.DevVoid
+    test.DevString                test.DevVarLongArray          
+    test.DevULong                 test.DevVarLongStringArray
+    
+    Spock <homer:10000> [3]: test.DevDouble(56.433)  # old style: test.command_inout("DevDouble").
+                 Result [3]: 56.433
+
+Tango classes as :class:`DeviceProxy`
+---------------------------------------------
+
+Spock exports all known tango classes as python alias to :class:`DeviceProxy`. 
+This way, if you want to create a device of class which you already know 
+(say, Libera, for example) you can do:
+
+.. sourcecode:: spock
+
+    Spock <homer:10000> [1]: lib01 = Libera("BO01/DI/BPM-01")
+
+One great advantage is that the tango device name completion is sensitive to the
+type of device you want to create. This means that if you are in the middle of
+writting a device name and you press the <tab> key, only devices of the tango
+class 'Libera' will show up as possible completions.
+
+.. sourcecode:: spock
+
+    Spock <homer:10000> [1]: bpm1 = Libera("<tab>
+    BO01/DI/BPM-01  BO01/DI/BPM-09  BO02/DI/BPM-06  BO03/DI/BPM-03  BO03/DI/BPM-11  BO04/DI/BPM-08
+    BO01/DI/BPM-02  BO01/DI/BPM-10  BO02/DI/BPM-07  BO03/DI/BPM-04  BO04/DI/BPM-01  BO04/DI/BPM-09
+    BO01/DI/BPM-03  BO01/DI/BPM-11  BO02/DI/BPM-08  BO03/DI/BPM-05  BO04/DI/BPM-02  BO04/DI/BPM-10
+    BO01/DI/BPM-04  BO02/DI/BPM-01  BO02/DI/BPM-09  BO03/DI/BPM-06  BO04/DI/BPM-03  BO04/DI/BPM-11
+    BO01/DI/BPM-05  BO02/DI/BPM-02  BO02/DI/BPM-10  BO03/DI/BPM-07  BO04/DI/BPM-04  
+    BO01/DI/BPM-06  BO02/DI/BPM-03  BO02/DI/BPM-11  BO03/DI/BPM-08  BO04/DI/BPM-05  
+    BO01/DI/BPM-07  BO02/DI/BPM-04  BO03/DI/BPM-01  BO03/DI/BPM-09  BO04/DI/BPM-06  
+    BO01/DI/BPM-08  BO02/DI/BPM-05  BO03/DI/BPM-02  BO03/DI/BPM-10  BO04/DI/BPM-07
+
+    Spock <homer:10000> [1]: bpm1 = Libera("BO01<tab>
+    BO01/DI/BPM-01  BO01/DI/BPM-03  BO01/DI/BPM-05  BO01/DI/BPM-07  BO01/DI/BPM-09  BO01/DI/BPM-11
+    BO01/DI/BPM-02  BO01/DI/BPM-04  BO01/DI/BPM-06  BO01/DI/BPM-08  BO01/DI/BPM-10
+    
+    Spock <homer:10000> [1]: bpm1 = Libera("BO01/DI/BPM-
+    
+    
+List tango devices, classes, servers
+------------------------------------
+
+Spock provides a set of magic functions (ipython lingo) that allow you to check
+for the list tango devices, classes and servers which are registered in the 
+current database.
+
+.. sourcecode:: spock
+
+    Spock <homer:10000> [1]: lsdev
+                                      Device                     Alias                    Server                Class
+    ---------------------------------------- ------------------------- ------------------------- --------------------
+                  expchan/BL99_Dummy0DCtrl/1                  BL99_0D1                 Pool/BL99      ZeroDExpChannel
+                      simulator/bl98/motor08                                      Simulator/BL98            SimuMotor
+                  expchan/BL99_Dummy0DCtrl/3                  BL99_0D3                 Pool/BL99      ZeroDExpChannel
+                  expchan/BL99_Dummy0DCtrl/2                  BL99_0D2                 Pool/BL99      ZeroDExpChannel
+                  expchan/BL99_Dummy0DCtrl/5                  BL99_0D5                 Pool/BL99      ZeroDExpChannel
+                  expchan/BL99_Dummy0DCtrl/4                  BL99_0D4                 Pool/BL99      ZeroDExpChannel
+                  expchan/BL99_Dummy0DCtrl/7                  BL99_0D7                 Pool/BL99      ZeroDExpChannel
+                  expchan/BL99_Dummy0DCtrl/6                  BL99_0D6                 Pool/BL99      ZeroDExpChannel
+                      simulator/bl98/motor01                                      Simulator/BL98            SimuMotor
+                      simulator/bl98/motor02                                      Simulator/BL98            SimuMotor
+                      simulator/bl98/motor03                                      Simulator/BL98            SimuMotor
+       mg/BL99/_mg_macserv_26065_-1320158352                                           Pool/BL99           MotorGroup
+                      simulator/bl98/motor05                                      Simulator/BL98            SimuMotor
+                      simulator/bl98/motor06                                      Simulator/BL98            SimuMotor
+                      simulator/bl98/motor07                                      Simulator/BL98            SimuMotor
+                    simulator/BL98/motctrl01                                      Simulator/BL98        SimuMotorCtrl
+                  expchan/BL99_Simu0DCtrl1/1                  BL99_0D8                 Pool/BL99      ZeroDExpChannel
+                 expchan/BL99_UxTimerCtrl1/1                BL99_Timer                 Pool/BL99         CTExpChannel
+    ...
+    
+    Spock <homer:10000> [1]: lsdevclass
+    SimuCoTiCtrl                   TangoAccessControl             ZeroDExpChannel
+    Door                           Motor                          DataBase
+    MotorGroup                     IORegister                     SimuMotorCtrl
+    TangoTest                      MacroServer                    TauTest
+    SimuMotor                      SimuCounterEx                  MeasurementGroup
+    Pool                           CTExpChannel
+
+    Spock <homer:10000> [1]: lsserv
+    MacroServer/BL99               MacroServer/BL98               Pool/V2
+    Pool/BL99                      Pool/BL98                      TangoTest/test
+    Pool/tcoutinho                 Simulator/BL98
+    TangoAccessControl/1           TauTest/tautest                DataBaseds/2
+    MacroServer/tcoutinho          Simulator/BL99
+
+Customized tango error message and introspection
+------------------------------------------------
+
+Spock intercepts tango exceptions that occur when you do tango operations 
+(ex.: write an attribute with a value outside the allowed limits) and tries to
+display it in a summarized, user friendly way.
+If you need more detailed information about the last tango error, you can use
+the magic command 'tango_error'.
+
+.. sourcecode:: spock
+
+    Spock <homer:10000> [1]: test = Device("sys/tg_test/1")
+
+    Spock <homer:10000> [2]: test.no_value
+    API_AttrValueNotSet : Read value for attribute no_value has not been updated
+    For more detailed information type: tango_error
+
+    Spock <homer:10000> [3]: tango_error
+    Last tango error:
+    DevFailed[
+    DevError[
+        desc = 'Read value for attribute no_value has not been updated'
+      origin = 'Device_3Impl::read_attributes_no_except'
+      reason = 'API_AttrValueNotSet'
+    severity = PyTango._PyTango.ErrSeverity.ERR]
+    DevError[
+        desc = 'Failed to read_attribute on device sys/tg_test/1, attribute no_value'
+      origin = 'DeviceProxy::read_attribute()'
+      reason = 'API_AttributeFailed'
+    severity = PyTango._PyTango.ErrSeverity.ERR]]
+
+Switching database
+------------------
+
+You can switch database simply by executing the 'switchdb <host> [<port>]' magic
+command.
+
+.. sourcecode:: spock
+
+    Spock <homer:10000> [1]: switchdb
+
+    Must give new database name in format <host>[:<port>].
+    <port> is optional. If not given it defaults to 10000.
+
+    Examples:
+    switchdb homer:10005
+    switchdb homer 10005
+    switchdb homer
+    
+    Spock <homer:10000> [2]: switchdb bart      # by default port is 10000
+    
+    Spock <bart:10000> [3]: switchdb lisa 10005  # you can use spaces between host and port
+    
+    Spock <lisa:10005> [4]: switchdb marge:10005 # or the traditional ':'
+
+Refreshing the database
+-----------------------
+
+When spock starts up or when the database is switched, a query is made to the
+tango Database device server which provides all necessary data. This
+data is stored locally in a spock cache which is used to provide all the nice 
+features.
+If the Database server is changed in some way (ex: a new device server is registered),
+the local database cache is not consistent anymore with the tango database.
+Therefore, spock provides a magic command 'refreshdb' that allows you to reread
+all tango information from the database.
+
+.. sourcecode:: spock
+
+    Spock <homer:10000> [1]: refreshdb
+    
+Storing your favorite tango objects for later usage
+---------------------------------------------------
+
+Since version 7.1.2, :class:`DeviceProxy`, :class:`AttributeProxy` and 
+:class:`Database` became pickable.
+This means that they can be used by the IPython_ 'store' magic command (type
+'store?' on the spock console to get information on how to use this command).
+You can, for example, assign your favorite devices in local python variables and
+then store these for the next time you startup IPython_ with spock profile.
+
+.. sourcecode:: spock
+
+    Spock <homer:10000> [1]: theta = Motor("BL99_M1")  # notice how we used tango alias
+    
+    Spock <homer:10000> [2]: store theta
+    Stored 'theta' (DeviceProxy)
+    
+    Spock <homer:10000> [3]: Ctrl+D
+    
+    (IPython session is closed and started again...)
+    
+    Spock <homer:10000> [1]: print theta
+    DeviceProxy(motor/bl99/1)
+    
+Tango color modes
+-----------------
+
+IPython_ (0.10) provides three color modes: 'Linux', 'NoColor' and 'LightBG'.
+Spock provides in addition 'Tango' (default), 'PurpleTango' (='Tango'),
+'BlueTango' and 'GreenTango'.
+
+You can switch between color modes online using the magic command 'colors'.
+
+.. sourcecode:: spock
+
+    Spock <homer:10000> [1]: colors BlueTango
+    
+    Spock <homer:10000> [2]: colors NoColor
+
+Adding spock to your own ipython profile
+----------------------------------------
+
+Adding spock to the ipython default profile
+###########################################
+
+Let's assume that you find spock so useful that each time you start ipython, you want
+spock features to be loaded by default.
+The way to do this is by editing your default ipython configuration file: 
+$HOME/.ipython/ipy_user_conf.py and add the lines 1 and 7.
+
+.. note::
+    The code shown below is a small part of your $HOME/.ipython/ipy_user_conf.py.
+    It is shown here only the relevant part for this example.
+
+.. sourcecode:: python
+
+    import PyTango.ipython
+
+    def main():
+
+        # uncomment if you want to get ipython -p sh behaviour
+        # without having to use command line switches  
+        # import ipy_profile_sh
+        PyTango.ipython.init_ipython(ip, console=False)
+
+And now, every time you start ipython::
+
+    ipython
+
+spock features will also be loaded.
+
+.. sourcecode:: ipython
+
+    In [1]: db
+    Out[1]: Database(homer, 10000)
+
+
+Adding spock to an existing customized profile
+##############################################
+
+If you have been working with IPython_ before and have already have defined a
+customized personal profile, you can extend your profile with spock features 
+without breaking your existing options. The trick is to initialize spock extension
+with a parameter that tells spock to maintain the existing options (like colors,
+command line and initial banner).
+
+So, for example, let's say you have created a profile called nuclear, and therefore
+you have a file called $HOME/.ipython/ipy_profile_nuclear.py with the following
+contents:
+
+.. sourcecode:: python
+
+    import os
+    import IPython.ipapi
+
+    def main():
+        ip = IPython.ipapi.get()
+        
+        o = ip.options
+        o.banner = "Springfield nuclear powerplant CLI\n\nWelcome Homer Simpson"
+        o.colors = "Linux"
+        o.prompt_in1 = "Mr. Burns owns you [\\#]: "
+        
+    main()
+
+In order to have spock features available to this profile you simply need to
+add two lines of code (lines 3 and 7):
+
+.. sourcecode:: python
+
+    import os
+    import IPython.ipapi
+    import PyTango.ipython
+
+    def main():
+        ip = IPython.ipapi.get()
+        PyTango.ipython.init_ipython(ip, console=False)
+        
+        o = ip.options
+        o.banner = "Springfield nuclear powerplant CLI\n\nMr. Burns owns you!"
+        o.colors = "Linux"
+        o.prompt_in1 = "The Simpsons [\\#]: "
+        
+    main()
+
+This will load the spock features into your profile while preserving your
+profile's console options (like colors, command line and initial banner).
+
+Creating a profile that extends spock profile
+#############################################
+
+It is also possible to create a profile that includes all spock features and at
+the same time adds new ones. Let's suppose that you want to create a customized
+profile called 'orbit' that automaticaly exports devices of class 
+'Libera' for the booster accelerator (assuming you are working on a synchrotron
+like institute ;-).
+Here is the code for the $HOME/.ipython/ipy_profile_orbit.py:
+
+.. sourcecode:: python
+
+    import os
+    import IPython.ipapi
+    import IPython.genutils
+    import IPython.ColorANSI
+    import PyTango.ipython
+    import StringIO
+
+    def magic_liberas(ip, p=''):
+        """Lists all known Libera devices."""
+        data = PyTango.ipython.get_device_map()
+        s = StringIO.StringIO()
+        cols = 30, 15, 20
+        l = "%{0}s %{1}s %{2}s".format(*cols)
+        print >>s, l % ("Device", "Alias", "Server")
+        print >>s, l % (cols[0]*"-", cols[1]*"-", cols[2]*"-")
+        for d, v in data.items():
+            if v[2] != 'Libera': continue
+            print >>s, l % (d, v[0], v[1])
+        s.seek(0)
+        IPython.genutils.page(s.read())
+
+    def main():
+        ip = IPython.ipapi.get()
+
+        PyTango.ipython.init_ipython(ip)
+
+        o = ip.options
+        
+        Colors = IPython.ColorANSI.TermColors
+        c = dict(Colors.__dict__)
+
+        o.banner += "\n{Brown}Welcome to Orbit analysis{Normal}\n".format(**c)
+
+        o.prompt_in1 = "Orbit [\\#]: "
+        o.colors = "BlueTango"
+        
+        ip.expose_magic("liberas", magic_liberas)
+
+        db = ip.user_ns.get('db')
+        dev_class_dict = PyTango.ipython.get_class_map()
+
+        if not dev_class_dict.has_key("Libera"):
+            return
+        
+        for libera in dev_class_dict['Libera']:
+            domain, family, member = libera.split("/")
+            var_name = domain + "_" + member
+            var_name = var_name.replace("-","_")
+            ip.to_user_ns( { var_name : PyTango.DeviceProxy(libera) } )
+
+    main()
+
+Then start your CLI with::
+
+    ipython -p orbit
+
+and you will have something like this
+
+.. image:: spock02.png
+
+Advanced event monitoring
+-------------------------
+
+With spock it is possible to monitor change events triggered by any tango
+attribute which has events enabled.
+
+To start monitoring the change events of an attribute:
+
+.. sourcecode:: spock
+
+    Spock <homer:10000> [1]: mon -a BL99_M1/Position
+    'BL99_M1/Position' is now being monitored. Type 'mon' to see all events
+    
+To list all events that have been intercepted:
+
+.. sourcecode:: spock
+
+    Spock <homer:10000> [2]: mon
+      ID           Device    Attribute            Value       Quality             Time
+    ---- ---------------- ------------ ---------------- ------------- ----------------
+       0     motor/bl99/1        state               ON    ATTR_VALID  17:11:08.026472
+       1     motor/bl99/1     position            190.0    ATTR_VALID  17:11:20.691112
+       2     motor/bl99/1        state           MOVING    ATTR_VALID  17:12:11.858985
+       3     motor/bl99/1     position    188.954072857 ATTR_CHANGING  17:12:11.987817
+       4     motor/bl99/1     position    186.045533882 ATTR_CHANGING  17:12:12.124448
+       5     motor/bl99/1     position    181.295838155 ATTR_CHANGING  17:12:12.260884
+       6     motor/bl99/1     position     174.55354729 ATTR_CHANGING  17:12:12.400036
+       7     motor/bl99/1     position     166.08870515 ATTR_CHANGING  17:12:12.536387
+       8     motor/bl99/1     position     155.77528943 ATTR_CHANGING  17:12:12.672846
+       9     motor/bl99/1     position    143.358230136 ATTR_CHANGING  17:12:12.811878
+      10     motor/bl99/1     position    131.476140017 ATTR_CHANGING  17:12:12.950391
+      11     motor/bl99/1     position    121.555421781 ATTR_CHANGING  17:12:13.087970
+      12     motor/bl99/1     position    113.457930987 ATTR_CHANGING  17:12:13.226531
+      13     motor/bl99/1     position    107.319423091 ATTR_CHANGING  17:12:13.363559
+      14     motor/bl99/1     position    102.928229946 ATTR_CHANGING  17:12:13.505102
+      15     motor/bl99/1     position    100.584726495 ATTR_CHANGING  17:12:13.640794
+      16     motor/bl99/1     position            100.0    ATTR_ALARM  17:12:13.738136
+      17     motor/bl99/1        state            ALARM    ATTR_VALID  17:12:13.743481
+
+    Spock <homer:10000> [3]: mon -l mot.* state
+      ID           Device    Attribute            Value       Quality             Time
+    ---- ---------------- ------------ ---------------- ------------- ----------------
+       0     motor/bl99/1        state               ON    ATTR_VALID  17:11:08.026472
+       2     motor/bl99/1        state           MOVING    ATTR_VALID  17:12:11.858985
+      17     motor/bl99/1        state            ALARM    ATTR_VALID  17:12:13.743481
+
+To stop monitoring the attribute:
+
+.. sourcecode:: spock
+
+    Spock <homer:10000> [1]: mon -d BL99_M1/Position
+    Stopped monitoring 'BL99_M1/Position'
+
+.. note::
+    Type 'mon?' to see detailed information about this magic command
+
+.. warning::
+     
+    Experimental: The monitor table can be shown in a GUI. For this feature to 
+    be available you need two things:
+
+        #. Have PyQt4 (>= 4.1) installed
+        #. Start spock with '-q4thread' support: 'ipython -q4thread -p spock'
+
+    When you type '%mon' the following table should appear:
+
+        .. image:: spock04.png
+
+.. _IPython: http://ipython.scipy.org/
+.. _Tango: http://www.tango-controls.org/
diff --git a/doc/spock/index.rst b/doc/spock/index.rst
new file mode 100644
index 0000000..90cbb29
--- /dev/null
+++ b/doc/spock/index.rst
@@ -0,0 +1,46 @@
+.. highlight:: python
+   :linenothreshold: 4
+
+.. _spock:
+
+Spock
+=====
+
+Spock is a PyTango CLI based on IPython_. It is designed to be used as an
+IPython extension or a profile [#ExtProfile]_.
+
+Spock is available since PyTango 7.1.2
+
+.. note::
+    'spock' used to be the name given to the CLI dedicated to Sardana. Now spock
+    became a generic Tango CLI and the connection to Sardana is provided as an
+    extension to spock. This sardana extension is NOT supplied by PyTango but is 
+    available from the Sardana package.
+
+You can start spock by typing on the command line::
+    
+    $ ipython -p spock
+
+and you should get something like this:
+
+.. image:: spock00.png
+
+.. toctree::
+    :maxdepth: 1
+
+    features
+    highlights
+
+--------------------------------------------------------------------------------
+
+.. [#ExtProfile] The difference between extension and profile is that an
+   extension is installed in the IPython installation extension directory and
+   therefore becomes available to all users of the machine automatically.
+   As a profile, it must be installed in each user's ipython configuration directory
+   (in linux, is usualy $HOME/.ipython).
+   Note that the spock profile is a very short (3 lines of code) python file.
+   See PyTango :ref:`build-install` for more information on how to install spock
+   as an extension or a profile.
+
+.. _IPython: http://ipython.scipy.org/
+.. _Tango: http://www.tango-controls.org/
\ No newline at end of file
diff --git a/doc/spock/spock00.png b/doc/spock/spock00.png
new file mode 100644
index 0000000..185c2a3
Binary files /dev/null and b/doc/spock/spock00.png differ
diff --git a/doc/spock/spock01.png b/doc/spock/spock01.png
new file mode 100644
index 0000000..e9975d8
Binary files /dev/null and b/doc/spock/spock01.png differ
diff --git a/doc/spock/spock02.png b/doc/spock/spock02.png
new file mode 100644
index 0000000..d50c853
Binary files /dev/null and b/doc/spock/spock02.png differ
diff --git a/doc/spock/spock03.png b/doc/spock/spock03.png
new file mode 100644
index 0000000..5c6cf90
Binary files /dev/null and b/doc/spock/spock03.png differ
diff --git a/doc/spock/spock04.png b/doc/spock/spock04.png
new file mode 100644
index 0000000..f8c7a5b
Binary files /dev/null and b/doc/spock/spock04.png differ
diff --git a/doc/start.rst b/doc/start.rst
new file mode 100644
index 0000000..ef0cced
--- /dev/null
+++ b/doc/start.rst
@@ -0,0 +1,250 @@
+.. highlight:: python
+   :linenothreshold: 5
+
+.. _getting-started:
+
+Getting started
+===============
+
+Quick installation
+------------------
+
+If you have all :ref:`dependencies <dependencies>` installed on your system,
+building and installing / updating PyTango can be as simple as::
+
+    easy_install -U PyTango
+
+.. _dependencies:
+
+If you managed to run this line, the :ref:`quick tour <quick-tour>` can guide
+you through the first steps on using PyTango.
+
+Dependencies on other libraries
+-------------------------------
+
+.. graphviz::
+
+    digraph dependencies {
+        size="6,3";
+        PyTango     [shape=box, label="PyTango 7.1.0"];
+        Python      [shape=box, label="Python >=2.4"];
+        boostpython [shape=box, label="boost python"];
+        boostp1     [shape=box, label="boost >=1.33"];
+        boostp2     [shape=box, label="boost >=1.41"];
+        Tango       [shape=box, label="Tango >=7.1"];
+        omniORB     [shape=box, label="omniORB >=4"];
+        numpy       [shape=box, label="numpy >=1.1.0"];
+        IPython     [shape=box, label="IPython >=0.10"];
+        PyTango -> Python;
+        PyTango -> Tango;
+        PyTango -> numpy [style=dotted, label="mandatory in windows"];
+        Tango -> omniORB;
+        PyTango -> boostpython
+        boostpython -> boostp1 [label="if python <2.6.3"];
+        boostpython -> boostp2 [label="if python >=2.6.3"];
+        PyTango -> IPython [style=dotted, label="optional"];
+    }   
+
+Don't be scared by the graph. Probably most of the packages are already installed.
+The current PyTango version has four major dependencies:
+
+- python (>= 2.4) (http://www.python.org/)
+- omniORB (http://omniorb.sourceforge.net/)
+- Tango (>= 7.1.0) (http://www.tango-controls.org/)
+  (really recommended 7.1.1)
+- boost python (http://www.boost.org):
+    if python >= 2.6.3 then: boost-python >= 1.41
+    else: boost-python >= 1.33
+    We **strongly** recommend always using >= 1.41
+  
+plus two optional dependencies (activated by default) on:
+
+- IPyhon (>=0.10) (http://ipython.scipy.org/) (necessary for :ref:`spock`)
+- numpy (>= 1.1.0) (http://numpy.scipy.org/)
+
+.. note::
+    For the provided windows binary, numpy is MANDATORY!
+
+Installing precompiled binaries
+-------------------------------
+
+The latest binaries for PyTango can be found at: http://www.tango-controls.org/download under
+the tango bindings section.
+
+Linux
+~~~~~
+
+The PyTango team does **not** provide a precompiled binary for Linux since this 
+would mean having to provide 12 different binaries: one for each major python 
+version (2.4, 2.5, 2.6, 2.7, 3.0 and 3.1) times 2 for both 32bits and 64bits.
+
+Windows
+~~~~~~~
+
+PyTango team provides a binary PyTango distributable for Windows XP/Vista 32bits 
+**for usage with python 2.6**.
+
+The binary **comes with its's own boost-python, omniORB and Tango DLLs**
+
++------------+-----------------------------------------------------------------+
+| version    | Includes the following DLLs                                     |
++============+=================================================================+
+| 7.1.0      | - tango 7.1.1 (VC++ 8)                                          |
+|            | - omniORB 4.1.4                                                 |
+|            | - boost python 1.41 (VC++8, multi-threaded)                     |
++------------+-----------------------------------------------------------------+
+| 7.1.0 rc1  | - tango 7.1.1 (VC++ 8)                                          |
+|            | - omniORB 4.1.4                                                 |
+|            | - boost python 1.41 beta 1 (VC++8, multi-threaded)              |
+|            |   this version was used because it is the first version that    |
+|            |   fixes a bug that prevents PyTango from being used with        | 
+|            |   python >= 2.6.3                                               |
++------------+-----------------------------------------------------------------+
+
+The binary was compiled with numpy dependency therefore you need to have *numpy*
+installed in order to use PyTango.
+
+Compiling & installing
+----------------------
+
+Linux
+~~~~~
+
+Since PyTango 7 the build system used to compile PyTango is the standard python 
+distutils.
+
+Besides the binaries for the four dependencies mentioned above, you also need 
+the development files for the respective libraries.
+
+boost python dependency
+#######################
+
+PyTango has a dependency on the boost python library (>= 1.33). This means that
+the shared library file **libboost-python.so** must be accessible to the 
+compilation command.
+
+.. note::
+
+    If you use python >= 2.6.3 you MUST install boost python >= 1.41
+
+Most linux distributions today provide a boost python package.
+
+Furthermore, in order to be able to build PyTango, you also need the include headers of
+boost python. They are normaly provided by a package called boost_python-dev.
+
+If, for some reason, you need to compile and install boost python, here is a 
+quick recipie:
+
+    #. Download latest boost tar.gz file and extract it
+    #. Download latest bjam (most linux distributions have a bjam package. If not, 
+       sourceforge provides a binary for many platforms)
+    #. build and/or install:
+    
+       #. Simple build: in the root directory where you extracted boost type:
+       
+          ``bjam --with-python toolset=gcc variant=release threading=multi link=shared``
+          
+          this will produce in :file:`bin.v2/libs/python/build/gcc-<gcc_ver>/release/threading-multi` a file called :file:`libboost_python-gcc<gcc_ver>-mt-<boost_ver>.so.<boost_python_ver>`
+          
+       #. Install (you may need administrator permissions to do so):
+       
+          ``bjam --with-python toolset=gcc variant=release threading=multi link=shared install``
+          
+       #. Install in a different directory (<install_dir>):
+       
+          ``bjam --with-python toolset=gcc variant=release threading=multi link=shared install --prefix=<install_dir>``
+
+
+boost, omniORB and TangoC++ configuration
+#########################################
+
+The second step is to make sure the three/four libraries (omniORB, tango, 
+boost python and/or numpy) are accessible to the compilation command. So, for 
+example, if you installed:
+
+    ``boost python under /home/homer/local``
+    
+    ``omniORB under /home/homer/local1``
+    
+    ``tango under /home/homer/local2``
+    
+    ``numpy under /usr/lib/python2.6/site-packages/numpy``
+    
+you must export the three environment variables::
+
+    export BOOST_ROOT=/home/homer/local
+    export OMNI_ROOT=/home/homer/local1
+    export TANGO_ROOT=/home/homer/local2
+    
+    # in openSUSE 11.1 this is the default base location for the include files
+    export NUMPY_ROOT=/usr/lib/python2.6/site-packages/numpy/core
+
+(for numpy this is the default base location for the include files. This is
+distribution dependent. For example, ubuntu places a numpy directory under /usr/include,
+so exporting NUMPY_ROOT is not necessary for this distribution)
+
+For the libraries that were installed in the default system directory (/usr or /usr/local)
+the above lines are not necessary.
+
+.. _build-install:
+
+build & install
+###############
+
+Finally::
+
+    python setup.py build
+    sudo python setup.py install
+    
+This will install PyTango in the system python installation directory and, since
+version 7.1.2, it will also install :ref:`spock` as an IPython_ extension.
+    
+Or if you whish to install in a different directory::
+    
+    python setup.py build
+    python setup.py install --prefix=/home/homer/local --ipython-local
+
+(This will try to install :ref:`spock` as an IPython profile to the local
+user, since probably there is no permission to write into the IPython_ extension
+directory)
+
+Or if you wish to use your own private python distribution::
+
+    /home/homer/bin/python setup.py build
+    /home/homer/bin/python setup.py install
+
+For the last case above don't forget that boost python should have also been 
+previously compiled with this private python distribution.
+
+test
+####
+
+If you have IPython_ installed, the best way to test your PyTango installation
+is by starting the new PyTango CLI called :ref:`spock` by typing on the command
+line::
+
+    $ ipython -p spock
+
+then, in spock type:
+
+.. sourcecode:: spock
+
+    Spock <homer:10000> [1]: PyTango.Release.version
+                 Result [1]: '7.1.2'
+
+(if you are wondering, :ref:`spock` automaticaly does ``import PyTango`` for you!)
+
+If you don't have IPython_ installed, to test the installation start a python console
+and type:
+
+    >>> import PyTango
+    >>> print PyTango.Release.version
+    7.1.2
+
+.. toctree::
+    :hidden:
+
+    Quick tour <quicktour>
+    Quick tour (original) <quicktour_old>
+    
+.. _IPython: http://ipython.scipy.org/
\ No newline at end of file
diff --git a/doc/title.png b/doc/title.png
new file mode 100644
index 0000000..e11cda8
Binary files /dev/null and b/doc/title.png differ
diff --git a/ez_setup.py b/ez_setup.py
new file mode 100644
index 0000000..1ff1d3e
--- /dev/null
+++ b/ez_setup.py
@@ -0,0 +1,284 @@
+#!python
+"""Bootstrap setuptools installation
+
+If you want to use setuptools in your package's setup.py, just include this
+file in the same directory with it, and add this to the top of your setup.py::
+
+    from ez_setup import use_setuptools
+    use_setuptools()
+
+If you want to require a specific version of setuptools, set a download
+mirror, or use an alternate download directory, you can do so by supplying
+the appropriate options to ``use_setuptools()``.
+
+This file can also be run as a script to install or upgrade setuptools.
+"""
+import sys
+DEFAULT_VERSION = "0.6c11"
+DEFAULT_URL     = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3]
+
+md5_data = {
+    'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca',
+    'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb',
+    'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b',
+    'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a',
+    'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618',
+    'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac',
+    'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5',
+    'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4',
+    'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c',
+    'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b',
+    'setuptools-0.6c10-py2.3.egg': 'ce1e2ab5d3a0256456d9fc13800a7090',
+    'setuptools-0.6c10-py2.4.egg': '57d6d9d6e9b80772c59a53a8433a5dd4',
+    'setuptools-0.6c10-py2.5.egg': 'de46ac8b1c97c895572e5e8596aeb8c7',
+    'setuptools-0.6c10-py2.6.egg': '58ea40aef06da02ce641495523a0b7f5',
+    'setuptools-0.6c11-py2.3.egg': '2baeac6e13d414a9d28e7ba5b5a596de',
+    'setuptools-0.6c11-py2.4.egg': 'bd639f9b0eac4c42497034dec2ec0c2b',
+    'setuptools-0.6c11-py2.5.egg': '64c94f3bf7a72a13ec83e0b24f2749b2',
+    'setuptools-0.6c11-py2.6.egg': 'bfa92100bd772d5a213eedd356d64086',
+    'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27',
+    'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277',
+    'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa',
+    'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e',
+    'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e',
+    'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f',
+    'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2',
+    'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc',
+    'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167',
+    'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64',
+    'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d',
+    'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20',
+    'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab',
+    'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53',
+    'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2',
+    'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e',
+    'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372',
+    'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902',
+    'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de',
+    'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b',
+    'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03',
+    'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a',
+    'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6',
+    'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a',
+}
+
+import sys, os
+try: from hashlib import md5
+except ImportError: from md5 import md5
+
+def _validate_md5(egg_name, data):
+    if egg_name in md5_data:
+        digest = md5(data).hexdigest()
+        if digest != md5_data[egg_name]:
+            print >>sys.stderr, (
+                "md5 validation of %s failed!  (Possible download problem?)"
+                % egg_name
+            )
+            sys.exit(2)
+    return data
+
+def use_setuptools(
+    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+    download_delay=15
+):
+    """Automatically find/download setuptools and make it available on sys.path
+
+    `version` should be a valid setuptools version number that is available
+    as an egg for download under the `download_base` URL (which should end with
+    a '/').  `to_dir` is the directory where setuptools will be downloaded, if
+    it is not already available.  If `download_delay` is specified, it should
+    be the number of seconds that will be paused before initiating a download,
+    should one be required.  If an older version of setuptools is installed,
+    this routine will print a message to ``sys.stderr`` and raise SystemExit in
+    an attempt to abort the calling script.
+    """
+    was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules
+    def do_download():
+        egg = download_setuptools(version, download_base, to_dir, download_delay)
+        sys.path.insert(0, egg)
+        import setuptools; setuptools.bootstrap_install_from = egg
+    try:
+        import pkg_resources
+    except ImportError:
+        return do_download()       
+    try:
+        pkg_resources.require("setuptools>="+version); return
+    except pkg_resources.VersionConflict, e:
+        if was_imported:
+            print >>sys.stderr, (
+            "The required version of setuptools (>=%s) is not available, and\n"
+            "can't be installed while this script is running. Please install\n"
+            " a more recent version first, using 'easy_install -U setuptools'."
+            "\n\n(Currently using %r)"
+            ) % (version, e.args[0])
+            sys.exit(2)
+        else:
+            del pkg_resources, sys.modules['pkg_resources']    # reload ok
+            return do_download()
+    except pkg_resources.DistributionNotFound:
+        return do_download()
+
+def download_setuptools(
+    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir,
+    delay = 15
+):
+    """Download setuptools from a specified location and return its filename
+
+    `version` should be a valid setuptools version number that is available
+    as an egg for download under the `download_base` URL (which should end
+    with a '/'). `to_dir` is the directory where the egg will be downloaded.
+    `delay` is the number of seconds to pause before an actual download attempt.
+    """
+    import urllib2, shutil
+    egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
+    url = download_base + egg_name
+    saveto = os.path.join(to_dir, egg_name)
+    src = dst = None
+    if not os.path.exists(saveto):  # Avoid repeated downloads
+        try:
+            from distutils import log
+            if delay:
+                log.warn("""
+---------------------------------------------------------------------------
+This script requires setuptools version %s to run (even to display
+help).  I will attempt to download it for you (from
+%s), but
+you may need to enable firewall access for this script first.
+I will start the download in %d seconds.
+
+(Note: if this machine does not have network access, please obtain the file
+
+   %s
+
+and place it in this directory before rerunning this script.)
+---------------------------------------------------------------------------""",
+                    version, download_base, delay, url
+                ); from time import sleep; sleep(delay)
+            log.warn("Downloading %s", url)
+            src = urllib2.urlopen(url)
+            # Read/write all in one block, so we don't create a corrupt file
+            # if the download is interrupted.
+            data = _validate_md5(egg_name, src.read())
+            dst = open(saveto,"wb"); dst.write(data)
+        finally:
+            if src: src.close()
+            if dst: dst.close()
+    return os.path.realpath(saveto)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+def main(argv, version=DEFAULT_VERSION):
+    """Install or upgrade setuptools and EasyInstall"""
+    try:
+        import setuptools
+    except ImportError:
+        egg = None
+        try:
+            egg = download_setuptools(version, delay=0)
+            sys.path.insert(0,egg)
+            from setuptools.command.easy_install import main
+            return main(list(argv)+[egg])   # we're done here
+        finally:
+            if egg and os.path.exists(egg):
+                os.unlink(egg)
+    else:
+        if setuptools.__version__ == '0.0.1':
+            print >>sys.stderr, (
+            "You have an obsolete version of setuptools installed.  Please\n"
+            "remove it from your system entirely before rerunning this script."
+            )
+            sys.exit(2)
+
+    req = "setuptools>="+version
+    import pkg_resources
+    try:
+        pkg_resources.require(req)
+    except pkg_resources.VersionConflict:
+        try:
+            from setuptools.command.easy_install import main
+        except ImportError:
+            from easy_install import main
+        main(list(argv)+[download_setuptools(delay=0)])
+        sys.exit(0) # try to force an exit
+    else:
+        if argv:
+            from setuptools.command.easy_install import main
+            main(argv)
+        else:
+            print "Setuptools version",version,"or greater has been installed."
+            print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
+
+def update_md5(filenames):
+    """Update our built-in md5 registry"""
+
+    import re
+
+    for name in filenames:
+        base = os.path.basename(name)
+        f = open(name,'rb')
+        md5_data[base] = md5(f.read()).hexdigest()
+        f.close()
+
+    data = ["    %r: %r,\n" % it for it in md5_data.items()]
+    data.sort()
+    repl = "".join(data)
+
+    import inspect
+    srcfile = inspect.getsourcefile(sys.modules[__name__])
+    f = open(srcfile, 'rb'); src = f.read(); f.close()
+
+    match = re.search("\nmd5_data = {\n([^}]+)}", src)
+    if not match:
+        print >>sys.stderr, "Internal error!"
+        sys.exit(2)
+
+    src = src[:match.start(1)] + repl + src[match.end(1):]
+    f = open(srcfile,'w')
+    f.write(src)
+    f.close()
+
+
+if __name__=='__main__':
+    if len(sys.argv)>2 and sys.argv[1]=='--md5update':
+        update_md5(sys.argv[2:])
+    else:
+        main(sys.argv[1:])
+
+
+
+
+
+
diff --git a/images/logo-2009.xcf b/images/logo-2009.xcf
new file mode 100644
index 0000000..341f6d4
Binary files /dev/null and b/images/logo-2009.xcf differ
diff --git a/images/logo-2010.png b/images/logo-2010.png
new file mode 100644
index 0000000..cd21332
Binary files /dev/null and b/images/logo-2010.png differ
diff --git a/images/logo-medium-2009.png b/images/logo-medium-2009.png
new file mode 100644
index 0000000..7bc4cc0
Binary files /dev/null and b/images/logo-medium-2009.png differ
diff --git a/images/logo-medium-2010.png b/images/logo-medium-2010.png
new file mode 100644
index 0000000..4877109
Binary files /dev/null and b/images/logo-medium-2010.png differ
diff --git a/images/logo-small-2009.png b/images/logo-small-2009.png
new file mode 100644
index 0000000..06b4527
Binary files /dev/null and b/images/logo-small-2009.png differ
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..1301565
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,399 @@
+#############################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## This is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Lesser General Public License as published by
+## the Free Software Foundation; either version 3 of the License, or
+## (at your option) any later version.
+##
+## This software is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU Lesser General Public License for more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program; if not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+import os
+import sys
+import errno
+import platform
+
+from ez_setup import use_setuptools
+use_setuptools()
+
+from setuptools import setup
+from setuptools import Extension, Distribution
+
+#from distutils.core import setup, Extension
+#from distutils.dist import Distribution
+import distutils.sysconfig
+
+
+try:
+    import sphinx
+except:
+    sphinx = None
+
+try:
+    import IPython
+    import IPython.genutils
+    _IPY_ROOT = os.path.dirname(os.path.abspath(IPython.__file__))
+    _IPY_LOCAL = str(IPython.genutils.get_ipython_dir())
+except:
+    IPython = None
+
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'PyTango'))
+
+from release import Release
+
+BOOST_ROOT = OMNI_ROOT = TANGO_ROOT = NUMPY_ROOT = '/usr'
+
+TANGO_ROOT = os.environ.get('TANGO_ROOT', TANGO_ROOT)
+OMNI_ROOT  = os.environ.get('OMNI_ROOT', OMNI_ROOT)
+BOOST_ROOT = os.environ.get('BOOST_ROOT', BOOST_ROOT)
+NUMPY_ROOT = os.environ.get('NUMPY_ROOT', NUMPY_ROOT)
+
+# if there is no numpy then for sure disable usage of it in PyTango
+
+numpy_capi_available = os.path.isdir(os.path.join(NUMPY_ROOT, 'include','numpy'))
+
+numpy_available = False
+try:
+    import numpy
+    numpy_available = True
+except Exception, e:
+    pass
+
+print '-- Compilation information -------------------------------------------'
+print 'Build %s %s' % (Release.name, Release.version_long)
+print 'Using Python %s' % distutils.sysconfig.get_python_version()
+print '\tinclude: %s' % distutils.sysconfig.get_python_inc()
+print '\tlibrary: %s' % distutils.sysconfig.get_python_lib()
+print 'Using omniORB from %s' % OMNI_ROOT
+print 'Using Tango from %s' % TANGO_ROOT
+print 'Using boost python from %s' % BOOST_ROOT
+if numpy_available:
+    if numpy_capi_available:
+        print 'Using numpy %s' % numpy.version.version
+        print '\tinclude: %s' % os.path.join(NUMPY_ROOT, 'include','numpy')
+    else:
+        print 'NOT using numpy (numpy available but C source is not)'
+else:
+    print 'NOT using numpy (it is not available)'
+print '----------------------------------------------------------------------'
+
+author = Release.authors['Coutinho']
+
+please_debug = False
+
+packages = [
+    'PyTango',
+    'PyTango.ipython',
+    'PyTango3'
+]
+
+provides = [
+    'PyTango',
+]
+
+requires = [
+    'boost_python (>=1.33)',
+    'numpy (>=1.1)'
+]
+
+package_data = {
+    'PyTango' : []
+}
+
+data_files = []
+
+classifiers = [
+    'Development Status :: 5 - Production/Stable',
+    'Environment :: Other Environment',
+    'Intended Audience :: Developers',
+    'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
+    'Natural Language :: English',
+    'Operating System :: Microsoft :: Windows',
+    'Operating System :: POSIX',
+    'Operating System :: POSIX :: Linux',
+    'Operating System :: Unix',
+    'Programming Language :: Python',
+    'Topic :: Scientific/Engineering',
+    'Topic :: Software Development :: Libraries',
+]
+
+def uniquify(seq):
+    no_dups = []
+    [ no_dups.append(i) for i in seq if not no_dups.count(i) ]
+    return no_dups
+
+include_dirs = [
+    os.path.abspath('src'),
+    os.path.join(TANGO_ROOT, 'include'),
+    os.path.join(OMNI_ROOT, 'include'),
+    os.path.join(NUMPY_ROOT, 'include'),
+]
+
+libraries = [
+        'tango',
+        'log4tango',
+    ]
+
+extra_compile_args = []
+
+extra_link_args = []
+
+macros = []
+
+if not numpy_available or not numpy_capi_available:
+    macros.append( ('DISABLE_PYTANGO_NUMPY', None) )
+
+library_dirs = [
+    os.path.join(TANGO_ROOT, 'lib'),
+    os.path.join(BOOST_ROOT, 'lib'),
+]
+
+if os.name == 'nt':
+    include_dirs += [ BOOST_ROOT ]
+
+    if please_debug:
+        libraries += [
+            #'libboost_python-vc80-mt-1_38', Boost in windows autodetects the
+            #proper library to link itself with...
+            'omniORB414d_rt',
+            'omniDynamic414d_rt',
+            'omnithread34d_rt',
+            'COS414d_rt',
+        ]
+        extra_compile_args += []
+        extra_link_args += ['/DEBUG']
+        macros += [ ('_DEBUG', None) ]
+    else:
+        libraries += [
+            #'libboost_python-vc80-mt-1_38', Boost in windows autodetects the
+            #proper library to link itself with...
+            'omniORB414_rt',
+            'omniDynamic414_rt',
+            'omnithread34_rt',
+            'COS414_rt',
+        ]
+
+    library_dirs += [ os.path.join(OMNI_ROOT, 'lib', 'x86_win32') ]
+    
+    extra_compile_args += [
+        '/EHsc'
+    ]
+
+    extra_link_args += []
+
+    macros += [
+        #('_WINDOWS', None),
+        #('_USRDLL', None),
+        #('_TANGO_LIB', None),
+        #('JPG_USE_ASM', None),
+        ('LOG4TANGO_HAS_DLL', None),
+        ('TANGO_HAS_DLL', None),
+        ('WIN32', None),
+    ]
+
+else:
+    if please_debug:
+        extra_compile_args += ['-g', '-O0']
+        extra_link_args += ['-g' , '-O0']
+    
+    include_dirs += [ os.path.join(BOOST_ROOT, 'include') ]
+    
+    libraries += [
+        'pthread',
+        'rt',
+        'dl',
+        'omniORB4',
+        'omniDynamic4',
+        'omnithread',
+        'COS4',
+    ]
+
+    # when building with multiple version of python on debian we need
+    # to link against boost_python-py25/-py26 etc...
+    pyver = "py" + "".join(map(str, platform.python_version_tuple()[:2]))
+    dist = platform.dist()[0].lower()
+    if dist in ['debian']:
+        libraries.append('boost_python-' + pyver)
+    else:
+        libraries.append('boost_python')
+
+    library_dirs += [ os.path.join(OMNI_ROOT, 'lib') ]
+
+
+    # Note for PyTango developers:
+    # Compilation time can be greatly reduced by compiling the file
+    # src/precompiled_header.hpp as src/precompiled_header.hpp.gch
+    # and then uncommenting this line. Someday maybe this will be
+    # automated...
+    extra_compile_args += [
+#        '-includesrc/precompiled_header.hpp',
+    ]
+
+    #if not please_debug:
+    #    extra_compile_args += [ '-g0' ]
+
+    extra_link_args += [
+        '-Wl,-h',
+        '-Wl,--strip-all',
+    ]
+
+    macros += []
+
+include_dirs = uniquify(include_dirs)
+library_dirs = uniquify(library_dirs)
+
+_cppfiles_exclude = []
+_cppfiles  = [ os.path.join('src',fname) for fname in os.listdir('src') if fname.endswith('.cpp') and not fname in _cppfiles_exclude]
+_cppfiles += [ os.path.join('src','server',fname) for fname in os.listdir(os.path.join('src','server')) if fname.endswith('.cpp') and not fname in _cppfiles_exclude]
+
+_pytango = Extension(name               = '_PyTango',
+                     sources            = _cppfiles,
+                     include_dirs       = include_dirs,
+                     library_dirs       = library_dirs,
+                     libraries          = libraries,
+                     define_macros      = macros,
+                     extra_compile_args = extra_compile_args,
+                     extra_link_args    = extra_link_args,
+                     language           = 'c++',
+                     depends            = []
+                     )
+
+from setuptools import Command
+#from distutils.cmd import Command
+from distutils.command.build import build as dftbuild
+from distutils.command.build_ext import build_ext as dftbuild_ext
+from distutils.unixccompiler import UnixCCompiler
+
+class build(dftbuild):
+
+    def has_doc(self):
+        if sphinx is None: return False
+        setup_dir = os.path.dirname(os.path.abspath(__file__))
+        return os.path.isdir(os.path.join(setup_dir, 'doc'))
+
+    def has_ipython(self):
+        return IPython is not None
+
+    sub_commands = dftbuild.sub_commands + [('build_doc', has_doc), ('build_spock', has_ipython)]
+
+cmdclass = {'build' : build }
+
+class build_ext(dftbuild_ext): 
+    
+    def build_extensions(self):
+        if isinstance(self.compiler, UnixCCompiler):
+            compiler_pars = self.compiler.compiler_so
+            while '-Wstrict-prototypes' in compiler_pars:
+                del compiler_pars[compiler_pars.index('-Wstrict-prototypes')]
+            #self.compiler.compiler_so = " ".join(compiler_pars)
+        dftbuild_ext.build_extensions(self)
+
+cmdclass['build_ext'] = build_ext
+
+if sphinx:
+    from sphinx.setup_command import BuildDoc
+
+    class build_doc(BuildDoc):
+        
+        def run(self):
+            # make sure the python path is pointing to the newly built
+            # code so that the documentation is built on this and not a
+            # previously installed version
+            build = self.get_finalized_command('build')
+            sys.path.insert(0, os.path.abspath(build.build_lib))
+            sphinx.setup_command.BuildDoc.run(self)
+            sys.path.pop(0)
+    
+    cmdclass['build_doc'] = build_doc
+
+if IPython:
+    class build_spock(Command):
+        
+        description = "Build Spock, the PyTango's IPython extension"
+
+        user_options = [
+            ('ipython-local', None, "install spock as current user profile instead of as an ipython extension"),
+            ('ipython-dir=', None, "Location of the ipython installation. (Defaults to '%s' if ipython-local is NOT set or to '%s' otherwise" % (_IPY_ROOT, _IPY_LOCAL) ) ]
+
+        boolean_options = [ 'ipython-local' ]
+
+        def initialize_options (self):
+            self.ipython_dir = None
+            self.ipython_local = False
+        
+        def finalize_options(self):
+            if self.ipython_dir is None:
+                if self.ipython_local:
+                    global _IPY_LOCAL
+                    self.ipython_dir = _IPY_LOCAL
+                else:
+                    global _IPY_ROOT
+                    self.ipython_dir = os.path.join(_IPY_ROOT, "Extensions")
+            else:
+                if ipython-local:
+                    self.warn("Both options 'ipython-dir' and 'ipython-local' were given. " \
+                              "'ipython-dir' will be used.")
+            self.ensure_dirname('ipython_dir')
+        
+        def run(self):
+            added_path = False
+            try:
+                # make sure the python path is pointing to the newly built
+                # code so that the documentation is built on this and not a
+                # previously installed version
+                build = self.get_finalized_command('build')
+                sys.path.insert(0, os.path.abspath(build.build_lib))
+                added_path=True
+                import PyTango.ipython
+                PyTango.ipython.install(self.ipython_dir, verbose=False)
+            except IOError, ioerr:
+                self.warn("Unable to install Spock IPython extension. Reason:")
+                self.warn(str(ioerr))
+                if ioerr.errno == errno.EACCES:
+                    self.warn("Probably you don't have enough previledges to install spock as an ipython extension.")
+                    self.warn("Try executing setup.py with sudo or otherwise give '--ipython-local' parameter to")
+                    self.warn("setup.py to install spock as a current user ipython profile.")
+                    self.warn("type: setup.py --help build_spock for more information")
+            except Exception, e:
+                self.warn("Unable to install Spock IPython extension. Reason:")
+                self.warn(str(e))
+                
+            if added_path:
+                sys.path.pop(0)
+            
+    cmdclass['build_spock'] = build_spock
+            
+dist = setup(
+    name             = 'PyTango',
+    version          = Release.version,
+    description      = Release.description,
+    long_description = Release.long_description,
+    author           = author[0],
+    author_email     = author[1],
+    url              = Release.url,
+    download_url     = Release.download_url,
+    platforms        = Release.platform,
+    license          = Release.license,
+    packages         = packages,
+    package_dir      = { 'PyTango' : 'PyTango', 'PyTango3' : 'PyTango3' },
+    classifiers      = classifiers,
+    package_data     = package_data,
+    data_files       = data_files,
+    provides         = provides,
+    keywords         = Release.keywords,
+    requires         = requires,
+    ext_package      = 'PyTango',
+    ext_modules      = [_pytango],
+    cmdclass         = cmdclass)
diff --git a/src/api_util.cpp b/src/api_util.cpp
new file mode 100644
index 0000000..7f6dfc8
--- /dev/null
+++ b/src/api_util.cpp
@@ -0,0 +1,54 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <boost/python/return_value_policy.hpp>
+#include <tango.h>
+
+#include "pyutils.h"
+
+using namespace boost::python;
+
+void (Tango::ApiUtil::*get_asynch_replies1)() = &Tango::ApiUtil::get_asynch_replies;
+void (Tango::ApiUtil::*get_asynch_replies2)(long) = &Tango::ApiUtil::get_asynch_replies;
+
+bool (Tango::ApiUtil::*in_server1)() = &Tango::ApiUtil::in_server;
+void (Tango::ApiUtil::*in_server2)(bool) = &Tango::ApiUtil::in_server;
+
+void export_api_util()
+{
+    class_<Tango::ApiUtil, boost::noncopyable>("ApiUtil", no_init)
+        
+        .def("instance", &Tango::ApiUtil::instance,
+            return_value_policy<reference_existing_object>())
+        .staticmethod("instance")
+        
+        .def("pending_asynch_call", &Tango::ApiUtil::pending_asynch_call)
+        
+        .def("get_asynch_replies", get_asynch_replies1)
+        .def("get_asynch_replies", get_asynch_replies2)
+        
+        .def("set_asynch_cb_sub_model", &Tango::ApiUtil::set_asynch_cb_sub_model)
+        .def("get_asynch_cb_sub_model", &Tango::ApiUtil::get_asynch_cb_sub_model)
+    ;
+}
\ No newline at end of file
diff --git a/src/archive_event_info.cpp b/src/archive_event_info.cpp
new file mode 100644
index 0000000..45c99b8
--- /dev/null
+++ b/src/archive_event_info.cpp
@@ -0,0 +1,36 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_archive_event_info()
+{
+    class_<Tango::ArchiveEventInfo>("ArchiveEventInfo")
+        .def_readwrite("archive_rel_change", &Tango::ArchiveEventInfo::archive_rel_change)
+        .def_readwrite("archive_abs_change", &Tango::ArchiveEventInfo::archive_abs_change)
+        .def_readwrite("extensions", &Tango::ArchiveEventInfo::extensions)
+    ;
+}
diff --git a/src/attr_conf_event_data.cpp b/src/attr_conf_event_data.cpp
new file mode 100644
index 0000000..d938c9d
--- /dev/null
+++ b/src/attr_conf_event_data.cpp
@@ -0,0 +1,51 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_attr_conf_event_data()
+{
+    class_<Tango::AttrConfEventData>("AttrConfEventData",
+        init<const Tango::AttrConfEventData &>())
+
+        // The original Tango::EventData structure has a 'device' field.
+        // However, if we returned this directly we would get a different
+        // python device each time. So we are doing our weird things to make
+        // sure the device returned is the same where the read action was
+        // performed. So we don't return Tango::EventData::device directly.
+        // See callback.cpp
+        .setattr("device",object())
+        .def_readonly("attr_name", &Tango::AttrConfEventData::attr_name)
+        .def_readonly("event", &Tango::AttrConfEventData::event)
+        .setattr("attr_conf",object())
+        .def_readonly("err", &Tango::AttrConfEventData::err)
+        .def_readonly("reception_date", &Tango::AttrConfEventData::reception_date)
+        .add_property("errors", make_getter(&Tango::AttrConfEventData::errors, 
+            return_value_policy<copy_non_const_reference>()))
+        .def("get_date", &Tango::AttrConfEventData::get_date,
+            return_internal_reference<>())
+    ;
+}
diff --git a/src/attribute_alarm_info.cpp b/src/attribute_alarm_info.cpp
new file mode 100644
index 0000000..ef5a18e
--- /dev/null
+++ b/src/attribute_alarm_info.cpp
@@ -0,0 +1,40 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_attribute_alarm_info()
+{
+    class_<Tango::AttributeAlarmInfo>("AttributeAlarmInfo")
+        .def_readwrite("min_alarm", &Tango::AttributeAlarmInfo::min_alarm)
+        .def_readwrite("max_alarm", &Tango::AttributeAlarmInfo::max_alarm)
+        .def_readwrite("min_warning", &Tango::AttributeAlarmInfo::min_warning)
+        .def_readwrite("max_warning", &Tango::AttributeAlarmInfo::max_warning)
+        .def_readwrite("delta_t", &Tango::AttributeAlarmInfo::delta_t)
+        .def_readwrite("delta_val", &Tango::AttributeAlarmInfo::delta_val)
+        .def_readwrite("extensions", &Tango::AttributeAlarmInfo::extensions)
+    ;
+}
diff --git a/src/attribute_dimension.cpp b/src/attribute_dimension.cpp
new file mode 100644
index 0000000..d180094
--- /dev/null
+++ b/src/attribute_dimension.cpp
@@ -0,0 +1,35 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_attribute_dimension()
+{
+    class_<Tango::AttributeDimension>("AttributeDimension")
+        .def_readonly("dim_x", &Tango::AttributeDimension::dim_x)
+        .def_readonly("dim_y", &Tango::AttributeDimension::dim_y)
+    ;
+}
diff --git a/src/attribute_event_info.cpp b/src/attribute_event_info.cpp
new file mode 100644
index 0000000..d51da67
--- /dev/null
+++ b/src/attribute_event_info.cpp
@@ -0,0 +1,36 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_attribute_event_info()
+{
+    class_<Tango::AttributeEventInfo>("AttributeEventInfo")
+       .def_readwrite("ch_event", &Tango::AttributeEventInfo::ch_event)
+       .def_readwrite("per_event", &Tango::AttributeEventInfo::per_event)
+       .def_readwrite("arch_event", &Tango::AttributeEventInfo::arch_event)
+    ;
+}
diff --git a/src/attribute_info.cpp b/src/attribute_info.cpp
new file mode 100644
index 0000000..5e77cf7
--- /dev/null
+++ b/src/attribute_info.cpp
@@ -0,0 +1,35 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_attribute_info()
+{
+    class_<Tango::AttributeInfo, bases<Tango::DeviceAttributeConfig> >
+        ("AttributeInfo")
+        .def_readonly("disp_level", &Tango::AttributeInfo::disp_level)
+    ;
+}
diff --git a/src/attribute_info_ex.cpp b/src/attribute_info_ex.cpp
new file mode 100644
index 0000000..e8cf698
--- /dev/null
+++ b/src/attribute_info_ex.cpp
@@ -0,0 +1,37 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_attribute_info_ex()
+{
+    class_<Tango::AttributeInfoEx, bases<Tango::AttributeInfo> >
+        ("AttributeInfoEx")
+        .def_readwrite("alarms", &Tango::AttributeInfoEx::alarms)
+        .def_readwrite("events", &Tango::AttributeInfoEx::events)
+        .def_readwrite("sys_extensions", &Tango::AttributeInfoEx::sys_extensions)
+    ;
+}
diff --git a/src/attribute_proxy.cpp b/src/attribute_proxy.cpp
new file mode 100644
index 0000000..dc3f3e4
--- /dev/null
+++ b/src/attribute_proxy.cpp
@@ -0,0 +1,124 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <boost/python/return_value_policy.hpp>
+#include <tango.h>
+#include <string>
+
+#include "defs.h"
+#include "pytgutils.h"
+
+using namespace boost::python;
+
+extern const char *param_must_be_seq;
+extern const char *unreachable_code;
+extern const char *non_string_seq;
+
+namespace PyAttributeProxy
+{
+    struct PickleSuite : pickle_suite
+    {
+        static tuple getinitargs(Tango::AttributeProxy& self)
+        {
+            Tango::DeviceProxy* dev = self.get_device_proxy();
+            
+            std::string ret = dev->get_db_host() + ":" + dev->get_db_port() + 
+                             "/" + dev->dev_name() + "/" + self.name();
+            return make_tuple(ret);
+        }
+    };
+}
+
+void export_attribute_proxy()
+{
+    // The following function declarations are necessary to be able to cast
+    // the function parameters from string& to const string&, otherwise python
+    // will not recognize the method calls
+
+    void (Tango::AttributeProxy::*get_property_)(std::string &, Tango::DbData &) =
+        &Tango::AttributeProxy::get_property;
+
+    void (Tango::AttributeProxy::*delete_property_)(std::string &) =
+        &Tango::AttributeProxy::delete_property;
+
+    class_<Tango::AttributeProxy> AttributeProxy(
+        "__AttributeProxy",
+        init<const char *>())
+    ;
+
+    AttributeProxy
+        .def(init<const Tango::DeviceProxy *, const char *>())
+        .def(init<const Tango::AttributeProxy &>())
+
+        //
+        // Pickle
+        //
+        .def_pickle(PyAttributeProxy::PickleSuite())
+        
+        //
+        // general methods
+        //
+
+        .def("name", &Tango::AttributeProxy::name,
+            ( arg_("self") ))
+
+        .def("get_device_proxy", &Tango::AttributeProxy::get_device_proxy,
+            ( arg_("self") ),
+            return_internal_reference<1>())
+
+        //
+        // property methods
+        //
+        .def("_get_property",
+            (void (Tango::AttributeProxy::*) (const std::string &, Tango::DbData &))
+            get_property_,
+            ( arg_("self"), arg_("propname"), arg_("propdata") ) )
+
+        .def("_get_property",
+            (void (Tango::AttributeProxy::*) (std::vector<std::string>&, Tango::DbData &))
+            &Tango::AttributeProxy::get_property,
+            ( arg_("self"), arg_("propnames"), arg_("propdata") ) )
+
+        .def("_get_property",
+            (void (Tango::AttributeProxy::*) (Tango::DbData &))
+            &Tango::AttributeProxy::get_property,
+            ( arg_("self"), arg_("propdata") ) )
+
+        .def("_put_property", &Tango::AttributeProxy::put_property,
+            ( arg_("self"), arg_("propdata") ) )
+
+        .def("_delete_property", (void (Tango::AttributeProxy::*) (const std::string &))
+            delete_property_,
+            ( arg_("self"), arg_("propname") ) )
+
+        .def("_delete_property", (void (Tango::AttributeProxy::*) (StdStringVector &))
+            &Tango::AttributeProxy::delete_property,
+            ( arg_("self"), arg_("propnames") ) )
+
+        .def("_delete_property", (void (Tango::AttributeProxy::*) (Tango::DbData &))
+            &Tango::AttributeProxy::delete_property,
+            ( arg_("self"), arg_("propdata") ) )
+    ;
+}
+
diff --git a/src/base_types.cpp b/src/base_types.cpp
new file mode 100644
index 0000000..b384de0
--- /dev/null
+++ b/src/base_types.cpp
@@ -0,0 +1,345 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+#include <tango.h>
+
+#include "defs.h"
+#include "pytgutils.h"
+
+#include "fast_from_py.h"
+#include "base_types_numpy.hpp"
+
+using namespace boost::python;
+
+// from tango_const.h
+void export_poll_device();
+
+// from devapi.h
+void export_locker_info();
+//TODO void export_locking_thread();
+void export_dev_command_info();
+void export_attribute_dimension();
+void export_command_info();
+void export_device_info();
+void export_device_attribute_config();
+void export_attribute_info();
+void export_attribute_alarm_info();
+void export_change_event_info();
+void export_periodic_event_info();
+void export_archive_event_info();
+void export_attribute_event_info();
+void export_attribute_info_ex();
+void export_device_data();
+void export_device_attribute();
+void export_device_data_history();
+void export_device_attribute_history();
+
+void export_dev_error();
+void export_time_val();
+
+//
+// Necessary equality operators for having vectors exported to python
+//
+
+namespace Tango
+{
+
+inline bool operator==(const Tango::DbDatum& dd1, const Tango::DbDatum& dd2)
+{
+    return dd1.name == dd2.name && dd1.value_string == dd2.value_string;
+}
+
+inline bool operator==(const Tango::DbDevInfo& di1, const Tango::DbDevInfo& di2)
+{
+    return di1.name == di2.name &&
+           di1._class == di2._class &&
+           di1.server == di2.server;
+}
+
+inline bool operator==(const Tango::DbDevImportInfo& dii1,
+                       const Tango::DbDevImportInfo& dii2)
+{
+    return dii1.name == dii2.name && dii1.exported == dii2.exported &&
+           dii1.ior == dii2.ior && dii1.version == dii2.version;
+}
+
+inline bool operator==(const Tango::DbDevExportInfo& dei1,
+                       const Tango::DbDevExportInfo& dei2)
+{
+    return dei1.name == dei2.name && dei1.ior == dei2.ior &&
+           dei1.host == dei2.host && dei1.version == dei2.version &&
+           dei1.pid == dei2.pid;
+}
+
+inline bool operator==(const Tango::DbHistory& dh1_, const Tango::DbHistory& dh2_)
+{
+    Tango::DbHistory &dh1 = const_cast<Tango::DbHistory &>(dh1_);
+    Tango::DbHistory &dh2 = const_cast<Tango::DbHistory &>(dh2_);
+
+    return dh1.get_name() == dh2.get_name() &&
+           dh1.get_attribute_name() == dh2.get_attribute_name() &&
+           dh1.is_deleted() == dh2.is_deleted();
+}
+
+inline bool operator==(const Tango::GroupReply& dh1_, const Tango::GroupReply& dh2_)
+{
+    /// @todo ?
+    return false;
+}
+
+inline bool operator==(const Tango::TimeVal& tv1, const Tango::TimeVal& tv2)
+{
+    return tv1.tv_sec == tv2.tv_sec &&
+           tv1.tv_usec == tv2.tv_usec &&
+           tv1.tv_nsec == tv2.tv_nsec;
+}
+
+inline bool operator==(const Tango::DeviceData& dd1_, const Tango::DeviceData& dd2_)
+{
+    Tango::DeviceData &dd1 = const_cast<Tango::DeviceData &>(dd1_);
+    Tango::DeviceData &dd2 = const_cast<Tango::DeviceData &>(dd2_);
+
+    return //dh1.any == dh2.any &&
+           dd1.exceptions() == dd2.exceptions();
+}
+
+inline bool operator==(const Tango::DeviceDataHistory& ddh1_, const Tango::DeviceDataHistory& ddh2_)
+{
+    Tango::DeviceDataHistory &ddh1 = const_cast<Tango::DeviceDataHistory &>(ddh1_);
+    Tango::DeviceDataHistory &ddh2 = const_cast<Tango::DeviceDataHistory &>(ddh2_);
+
+    return operator==((Tango::DeviceData)ddh1, (Tango::DeviceData)ddh2) &&
+           ddh1.failed() == ddh2.failed() &&
+           ddh1.date() == ddh2.date(); //&&
+           //ddh1.errors() == ddh2.errors();
+}
+
+}
+
+/**
+ * Converter from python sequence to CORBA sequence
+ */
+template<typename CorbaSequence>
+struct convert_PySequence_to_CORBA_Sequence
+{
+    convert_PySequence_to_CORBA_Sequence()
+    {
+        // Register converter from python sequence to CorbaSequence
+        boost::python::converter::registry::push_back(
+            &convertible,
+            &construct,
+            boost::python::type_id<CorbaSequence>());
+    }
+
+    // Check if given Python object is convertible to a sequence.
+    // If so, return obj, otherwise return 0
+    static void* convertible(PyObject* obj)
+    {
+        return (PySequence_Check(obj)) ? obj : NULL;
+    }
+
+    static void construct(PyObject* obj,
+                          boost::python::converter::rvalue_from_python_stage1_data* data)
+    {
+            
+        typedef boost::python::converter::rvalue_from_python_storage<CorbaSequence> CorbaSequence_storage;
+
+        void* const storage = reinterpret_cast<CorbaSequence_storage*>(data)->storage.bytes;
+
+        CorbaSequence *ptr = new (storage) CorbaSequence();
+        convert2array(object(handle<>(obj)), *ptr);
+        data->convertible = storage;
+    }
+    
+};
+
+int raise_asynch_exception(long thread_id, boost::python::object exp_klass)
+{
+    return PyThreadState_SetAsyncExc(thread_id, exp_klass.ptr());
+}
+
+void export_base_types()
+{
+    enum_<PyTango::ExtractAs>("ExtractAs")
+        .value("Numpy", PyTango::ExtractAsNumpy)
+        .value("Tuple", PyTango::ExtractAsTuple)
+        .value("List", PyTango::ExtractAsList)
+        .value("String", PyTango::ExtractAsString)
+        .value("PyTango3", PyTango::ExtractAsPyTango3)
+        .value("Nothing", PyTango::ExtractAsNothing)
+    ;
+    
+    // Export some std types
+
+    // vector_indexing_suite<*, true | false>:
+    //  - true:  Make a copy of the original value each time the vector
+    //           is accessed. We have a struct like this:
+    //              struct V { int value; }
+    //            and the object is:
+    //              std::vector<V> vec = { 69 };
+    //            wrapped in python and we do:
+    //              vec[0].value = 3
+    //              vec[0].unexisting = 7
+    //              print vec[0].value
+    //              >> 69 ( 3 is stored in the obj created the first vec[0])
+    //              print vec[0].unexisting
+    //              >> exception (unexisting is stored in the other obj)
+    //           If the C struct has a 'value' field, it will
+    //  - false: Make a new proxy object of the original value each time
+    //           the vector is accessed. With the same example:
+    //              vec[0].value = 3
+    //              vec[0].unexisting = 7
+    //              print vec[0].value
+    //              >> 3 (It's another proxy obj, but modifiyes the same
+    //                   internal C object)
+    //              print vec[0].unexisting
+    //              >> exception (unexisting is stored in the other obj)
+
+    class_<StdStringVector>("StdStringVector")
+        .def(vector_indexing_suite<StdStringVector, true>());
+
+    class_<StdLongVector>("StdLongVector")
+        .def(vector_indexing_suite<StdLongVector, true>());
+
+    class_<StdDoubleVector>("StdDoubleVector")
+        .def(vector_indexing_suite<StdDoubleVector, true>());
+
+    class_<Tango::CommandInfoList>("CommandInfoList")
+        .def(vector_indexing_suite<Tango::CommandInfoList, false>());
+
+    class_<Tango::AttributeInfoList>("AttributeInfoList")
+        .def(vector_indexing_suite<Tango::AttributeInfoList, false>());
+
+    class_<Tango::AttributeInfoListEx>("AttributeInfoListEx")
+        .def(vector_indexing_suite<Tango::AttributeInfoListEx, false>());
+
+    class_<std::vector<Tango::Attr *> >("AttrList")
+        .def(vector_indexing_suite<std::vector<Tango::Attr *>, true>());
+
+    //class_<Tango::EventDataList>("EventDataList")
+    //    .def(vector_indexing_suite<Tango::EventDataList>());
+
+    class_<Tango::DbData>("DbData")
+        .def(vector_indexing_suite<Tango::DbData, true>());
+
+    class_<Tango::DbDevInfos>("DbDevInfos")
+        .def(vector_indexing_suite<Tango::DbDevInfos, true>());
+
+    class_<Tango::DbDevExportInfos>("DbDevExportInfos")
+        .def(vector_indexing_suite<Tango::DbDevExportInfos, true>());
+
+    class_<Tango::DbDevImportInfos>("DbDevImportInfos")
+        .def(vector_indexing_suite<Tango::DbDevImportInfos, true>());
+
+    class_<std::vector<Tango::DbHistory> >("DbHistoryList")
+        .def(vector_indexing_suite<std::vector<Tango::DbHistory>, true>());
+
+    class_<Tango::DeviceDataHistoryList>("DeviceDataHistoryList")
+        .def(vector_indexing_suite<Tango::DeviceDataHistoryList, true>());
+
+    typedef std::vector<Tango::GroupReply> StdGroupReplyVector_;
+    class_< StdGroupReplyVector_ >("StdGroupReplyVector")
+        .def(vector_indexing_suite<StdGroupReplyVector_, true>());
+
+    typedef std::vector<Tango::GroupCmdReply> StdGroupCmdReplyVector_;
+    class_< StdGroupCmdReplyVector_ >("StdGroupCmdReplyVector")
+        .def(vector_indexing_suite<StdGroupCmdReplyVector_, true>());
+
+    typedef std::vector<Tango::GroupAttrReply> StdGroupAttrReplyVector_;
+    class_< StdGroupAttrReplyVector_ >("StdGroupAttrReplyVector")
+        .def(vector_indexing_suite<StdGroupAttrReplyVector_, true>());
+
+    //to_python_converter<CORBA::String_member, CORBA_String_member_to_str>();
+    to_python_converter<_CORBA_String_member, CORBA_String_member_to_str2>();
+    to_python_converter<_CORBA_String_element, CORBA_String_element_to_str>();
+
+    to_python_converter<Tango::DevErrorList, CORBA_sequence_to_tuple<Tango::DevErrorList> >();
+
+    to_python_converter<Tango::DevVarCharArray, CORBA_sequence_to_list<Tango::DevVarCharArray> >();
+    to_python_converter<Tango::DevVarShortArray, CORBA_sequence_to_list<Tango::DevVarShortArray> >();
+    to_python_converter<Tango::DevVarLongArray, CORBA_sequence_to_list<Tango::DevVarLongArray> >();
+    to_python_converter<Tango::DevVarFloatArray, CORBA_sequence_to_list<Tango::DevVarFloatArray> >();
+    to_python_converter<Tango::DevVarDoubleArray, CORBA_sequence_to_list<Tango::DevVarDoubleArray> >();
+    to_python_converter<Tango::DevVarUShortArray, CORBA_sequence_to_list<Tango::DevVarUShortArray> >();
+    to_python_converter<Tango::DevVarULongArray, CORBA_sequence_to_list<Tango::DevVarULongArray> >();
+    to_python_converter<Tango::DevVarStringArray, CORBA_sequence_to_list<Tango::DevVarStringArray> >();
+    to_python_converter<Tango::DevVarLongStringArray, CORBA_sequence_to_list<Tango::DevVarLongStringArray> >();
+    to_python_converter<Tango::DevVarDoubleStringArray, CORBA_sequence_to_list<Tango::DevVarDoubleStringArray> >();
+    to_python_converter<Tango::DevVarLong64Array, CORBA_sequence_to_list<Tango::DevVarLong64Array> >();
+    to_python_converter<Tango::DevVarULong64Array, CORBA_sequence_to_list<Tango::DevVarULong64Array> >();
+
+    //to_python_converter<unsigned char, UChar_to_str>();
+    
+    convert_PySequence_to_CORBA_Sequence<Tango::DevVarCharArray>();
+    convert_PySequence_to_CORBA_Sequence<Tango::DevVarShortArray>();
+    convert_PySequence_to_CORBA_Sequence<Tango::DevVarLongArray>();
+    convert_PySequence_to_CORBA_Sequence<Tango::DevVarFloatArray>();
+    convert_PySequence_to_CORBA_Sequence<Tango::DevVarDoubleArray>();
+    convert_PySequence_to_CORBA_Sequence<Tango::DevVarUShortArray>();
+    convert_PySequence_to_CORBA_Sequence<Tango::DevVarULongArray>();
+    convert_PySequence_to_CORBA_Sequence<Tango::DevVarStringArray>();
+    convert_PySequence_to_CORBA_Sequence<Tango::DevVarLongStringArray>();
+    convert_PySequence_to_CORBA_Sequence<Tango::DevVarDoubleStringArray>();
+    convert_PySequence_to_CORBA_Sequence<Tango::DevVarLong64Array>();
+    convert_PySequence_to_CORBA_Sequence<Tango::DevVarULong64Array>();
+
+    convert_numpy_to_integer<Tango::DEV_UCHAR>();
+    convert_numpy_to_integer<Tango::DEV_SHORT>();
+    convert_numpy_to_integer<Tango::DEV_LONG>();
+    convert_numpy_to_float<Tango::DEV_FLOAT>();
+    convert_numpy_to_float<Tango::DEV_DOUBLE>();
+    convert_numpy_to_integer<Tango::DEV_USHORT>();
+    convert_numpy_to_integer<Tango::DEV_ULONG>();
+    convert_numpy_to_integer<Tango::DEV_LONG64>();
+    convert_numpy_to_integer<Tango::DEV_ULONG64>();
+    
+    // from tango_const.h
+    export_poll_device();
+
+    // from devapi.h
+    export_locker_info();
+    //TODO export_locking_thread();
+    export_dev_command_info();
+    export_attribute_dimension();
+    export_command_info();
+    export_device_info();
+    export_device_attribute_config();
+    export_attribute_info();
+    export_attribute_alarm_info();
+    export_change_event_info();
+    export_periodic_event_info();
+    export_archive_event_info();
+    export_attribute_event_info();
+    export_attribute_info_ex();
+    export_device_data();
+    export_device_attribute();
+    export_device_data_history();
+    export_device_attribute_history();
+
+    export_dev_error();
+    export_time_val();
+    
+    def("raise_asynch_exception", &raise_asynch_exception);
+}
diff --git a/src/base_types_numpy.hpp b/src/base_types_numpy.hpp
new file mode 100644
index 0000000..375f70e
--- /dev/null
+++ b/src/base_types_numpy.hpp
@@ -0,0 +1,131 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#pragma once
+
+#ifdef DISABLE_PYTANGO_NUMPY
+
+template<long tangoTypeConst>
+struct convert_numpy_to_integer {
+    convert_numpy_to_integer() {}
+};
+
+template<long tangoTypeConst>
+struct convert_numpy_to_float {
+    convert_numpy_to_float() {}
+};
+
+#else
+
+template<long tangoTypeConst>
+struct convert_numpy_to_integer
+{
+    typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+    static const long NumpyType = TANGO_const2numpy(tangoTypeConst);
+
+    convert_numpy_to_integer()
+    {
+        boost::python::converter::registry::push_back(
+            &convertible,
+            &construct,
+            boost::python::type_id<TangoScalarType>());
+    }
+
+    static void* convertible(PyObject* obj)
+    {
+        if (!PyArray_CheckScalar(obj))
+            return 0;
+
+        PyArray_Descr* type = PyArray_DescrFromScalar(obj);
+        if (PyDataType_ISINTEGER(type)) {
+            return obj;
+        }
+        return 0;
+    }
+
+    static void construct(PyObject* obj,
+                          boost::python::converter::rvalue_from_python_stage1_data* data)
+    {
+        typedef boost::python::converter::rvalue_from_python_storage<TangoScalarType> tango_storage;
+        void* const storage = reinterpret_cast<tango_storage*>(data)->storage.bytes;
+        TangoScalarType *ptr = new (storage) TangoScalarType();
+
+        PyObject* native_obj = PyObject_CallMethod(obj, const_cast<char*>("__int__"), NULL);
+        if (native_obj == NULL) {
+            boost::python::throw_error_already_set();
+        }
+        from_py<tangoTypeConst>::convert(native_obj, *ptr);
+        Py_DECREF(native_obj);
+
+        data->convertible = storage;
+    }
+
+};
+
+
+
+template<long tangoTypeConst>
+struct convert_numpy_to_float
+{
+    typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+    static const long NumpyType = TANGO_const2numpy(tangoTypeConst);
+
+    convert_numpy_to_float()
+    {
+        boost::python::converter::registry::push_back(
+            &convertible,
+            &construct,
+            boost::python::type_id<TangoScalarType>());
+    }
+
+    static void* convertible(PyObject* obj)
+    {
+        if (!PyArray_CheckScalar(obj))
+            return 0;
+
+        PyArray_Descr* type = PyArray_DescrFromScalar(obj);
+        if (PyDataType_ISINTEGER(type) || PyDataType_ISFLOAT(type)) {
+            return obj;
+        }
+        return 0;
+    }
+
+    static void construct(PyObject* obj,
+                          boost::python::converter::rvalue_from_python_stage1_data* data)
+    {
+        typedef boost::python::converter::rvalue_from_python_storage<TangoScalarType> tango_storage;
+        void* const storage = reinterpret_cast<tango_storage*>(data)->storage.bytes;
+        TangoScalarType *ptr = new (storage) TangoScalarType();
+
+        PyObject* native_obj = PyObject_CallMethod(obj, const_cast<char*>("__float__"), NULL);
+        if (native_obj == NULL) {
+            boost::python::throw_error_already_set();
+        }
+        from_py<tangoTypeConst>::convert(native_obj, *ptr);
+        Py_DECREF(native_obj);
+
+        data->convertible = storage;
+    }
+};
+
+#endif
diff --git a/src/callback.cpp b/src/callback.cpp
new file mode 100644
index 0000000..36c3421
--- /dev/null
+++ b/src/callback.cpp
@@ -0,0 +1,386 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+#include "pytgutils.h"
+#include "callback.h"
+#include "device_attribute.h"
+#include "exception.h"
+
+using namespace boost::python;
+
+struct PyCmdDoneEvent {
+    object device;
+    object cmd_name;
+    object argout;
+    object argout_raw;
+    object err;
+    object errors;
+    object ext;
+};
+
+struct PyAttrReadEvent {
+    object device;
+    object attr_names;
+    object argout;
+    object err;
+    object errors;
+    object ext;
+};
+
+struct PyAttrWrittenEvent {
+    object device;
+    object attr_names;
+    object err;
+    object errors;
+    object ext;
+};
+
+
+static void copy_most_fields(PyCallBackAutoDie* self, const Tango::CmdDoneEvent* ev, PyCmdDoneEvent* py_ev)
+{
+    // py_ev->device
+    py_ev->cmd_name = object(ev->cmd_name);
+    py_ev->argout_raw = object(ev->argout);
+    py_ev->err = object(ev->err);
+    py_ev->errors = object(ev->errors);
+    // py_ev->ext = object(ev->ext);
+}
+
+static void copy_most_fields(PyCallBackAutoDie* self, const Tango::AttrReadEvent* ev, PyAttrReadEvent* py_ev)
+{
+    // py_ev->device
+    py_ev->attr_names = object(ev->attr_names);
+
+    PyDeviceAttribute::AutoDevAttrVector dev_attr_vec(ev->argout);
+    py_ev->argout = PyDeviceAttribute::convert_to_python( \
+                            dev_attr_vec, *ev->device, self->m_extract_as);
+
+    py_ev->err = object(ev->err);
+    py_ev->errors = object(ev->errors);
+    // py_ev->ext = object(ev->ext);
+}
+
+static void copy_most_fields(PyCallBackAutoDie* self, const Tango::AttrWrittenEvent* ev, PyAttrWrittenEvent* py_ev)
+{
+    // py_ev->device
+    py_ev->attr_names = object(ev->attr_names);
+    py_ev->err = object(ev->err);
+    py_ev->errors = object(ev->errors);
+    // py_ev->ext = object(ev->ext);
+}
+
+/*static*/ object PyCallBackAutoDie::py_on_callback_parent_fades;
+/*static*/ std::map<PyObject*, PyObject*> PyCallBackAutoDie::s_weak2ob;
+
+PyCallBackAutoDie::~PyCallBackAutoDie()
+{
+    if (this->m_weak_parent) {
+        PyCallBackAutoDie::s_weak2ob.erase(this->m_weak_parent);
+        boost::python::xdecref(this->m_weak_parent);
+    }
+}
+
+
+
+/*static*/ void PyCallBackAutoDie::init()
+{
+    object py_scope = boost::python::scope();
+
+    def ("__on_callback_parent_fades", on_callback_parent_fades);
+    PyCallBackAutoDie::py_on_callback_parent_fades = py_scope.attr("__on_callback_parent_fades");
+}
+
+void PyCallBackAutoDie::on_callback_parent_fades(PyObject* weakobj)
+{
+    PyObject* ob = PyCallBackAutoDie::s_weak2ob[weakobj];
+
+    if (!ob)
+        return;
+
+//     while (ob->ob_refcnt)
+    boost::python::xdecref(ob);
+}
+
+void PyCallBackAutoDie::set_autokill_references(object &py_self, object &py_parent)
+{
+    if (m_self == 0)
+        m_self = py_self.ptr();
+
+    assert(m_self == py_self.ptr());
+
+    PyObject* recb = PyCallBackAutoDie::py_on_callback_parent_fades.ptr();
+    this->m_weak_parent = PyWeakref_NewRef(py_parent.ptr(), recb);
+
+    if (!this->m_weak_parent)
+        throw_error_already_set();
+
+    boost::python::incref(this->m_self);
+    PyCallBackAutoDie::s_weak2ob[this->m_weak_parent] = py_self.ptr();
+}
+
+void PyCallBackAutoDie::unset_autokill_references()
+{
+    boost::python::decref(m_self);
+}
+
+
+template<typename OriginalT, typename CopyT>
+static void _run_virtual_once(PyCallBackAutoDie* self, OriginalT * ev, const char* virt_fn_name)
+{
+    AutoPythonGIL gil;
+
+    try {
+        CopyT* py_ev = new CopyT();
+        object py_value = object( handle<>(
+                    to_python_indirect<
+                        CopyT*,
+                        detail::make_owning_holder>()(py_ev) ) );
+
+        // - py_ev->device = object(ev->device); No, we use m_weak_parent
+        // so we get exactly the same python object...
+        if (self->m_weak_parent) {
+            PyObject* parent = PyWeakref_GET_OBJECT(self->m_weak_parent);
+            if (parent && parent != Py_None) {
+                py_ev->device = object(handle<>(borrowed(parent)));
+            }
+        }
+
+        copy_most_fields(self, ev, py_ev);
+
+        self->get_override(virt_fn_name)(py_value);
+    } catch (...) {
+        self->unset_autokill_references();
+        /// @todo yes, I want the exception to go to Tango and then wathever. But it will make a memory leak bcos tangoc++ is not handling exceptions properly!!  (proxy_asyn_cb.cpp, void Connection::Cb_ReadAttr_Request(CORBA::Request_ptr req,Tango::CallBack *cb_ptr))
+        /// and the same for cmd_ended, attr_read & attr_written
+        /// @bug See previous todo. If TangoC++ is fixed, it'll become a bug:
+        delete ev;
+        /// @todo or maybe it's just that I am not supposed to re-throw the exception? (still a bug in tangoc++). Then also get rid of the "delete ev" line!
+        throw;
+    }
+    self->unset_autokill_references();
+};
+
+/*virtual*/ void PyCallBackAutoDie::cmd_ended(Tango::CmdDoneEvent * ev)
+{
+    _run_virtual_once<Tango::CmdDoneEvent, PyCmdDoneEvent>(this, ev, "cmd_ended");
+};
+
+/*virtual*/ void PyCallBackAutoDie::attr_read(Tango::AttrReadEvent *ev)
+{
+    _run_virtual_once<Tango::AttrReadEvent, PyAttrReadEvent>(this, ev, "attr_read");
+};
+
+/*virtual*/ void PyCallBackAutoDie::attr_written(Tango::AttrWrittenEvent *ev)
+{
+    _run_virtual_once<Tango::AttrWrittenEvent, PyAttrWrittenEvent>(this, ev, "attr_written");
+};
+
+
+
+PyCallBackPushEvent::~PyCallBackPushEvent()
+{
+    boost::python::xdecref(this->m_weak_device);
+}
+
+void PyCallBackPushEvent::set_device(object &py_device)
+{
+    this->m_weak_device = PyWeakref_NewRef(py_device.ptr(), 0);
+
+    if (!this->m_weak_device)
+        throw_error_already_set();
+}
+
+
+namespace {
+
+    template<typename OriginalT>
+    void copy_device(OriginalT* ev, object py_ev, object py_device)
+    {
+        if (py_device.ptr() != Py_None)
+            py_ev.attr("device") = py_device;
+        else
+            py_ev.attr("device") = object(ev->device);
+    }
+
+    template<typename OriginalT>
+    static void _push_event(PyCallBackPushEvent* self, OriginalT * ev)
+    {
+        // If the event is received after python dies but before the process
+        // finishes then discard the event
+        if (!Py_IsInitialized())
+        {
+            cout4 << "Tango event (" << ev->event << " for " 
+                  << ev->attr_name << ") received for after python shutdown. "
+                  << "Event will be ignored" << std::endl;
+            return;
+        }
+        
+        AutoPythonGIL gil;
+
+        // Make a copy of ev in python
+        // (the original will be deleted by TangoC++ on return)
+        object py_ev(ev);
+        OriginalT* ev_copy = extract<OriginalT*>(py_ev);
+
+        // If possible, reuse the original DeviceProxy
+        object py_device;
+        if (self->m_weak_device) {
+            PyObject* py_c_device = PyWeakref_GET_OBJECT(self->m_weak_device);
+            if (py_c_device && py_c_device != Py_None)
+                py_device = object(handle<>(borrowed(py_c_device)));
+        }
+
+        try
+        {
+            PyCallBackPushEvent::fill_py_event(ev_copy, py_ev, py_device, self->m_extract_as);
+        }
+        SAFE_CATCH_REPORT("PyCallBackPushEvent::fill_py_event")
+
+        try
+        {
+            self->get_override("push_event")(py_ev);
+        }
+        SAFE_CATCH_INFORM("push_event")
+    };
+}
+
+
+
+void PyCallBackPushEvent::fill_py_event(Tango::EventData* ev, object & py_ev, object py_device, PyTango::ExtractAs extract_as)
+{
+    copy_device(ev, py_ev, py_device);
+    /// @todo on error extracting, we could save the error in DeviceData
+    /// instead of throwing it...?
+    // Save a copy of attr_value, so we can still access it after
+    // the execution of the callback (Tango will delete the original!)
+    // I originally was 'stealing' the reference to TangoC++: I got
+    // attr_value and set it to 0... But now TangoC++ is not deleting
+    // attr_value pointer but its own copy, so my efforts are useless.
+    if (ev->attr_value)
+    {
+        Tango::DeviceAttribute *attr = new Tango::DeviceAttribute(*ev->attr_value);
+        py_ev.attr("attr_value") = PyDeviceAttribute::convert_to_python(attr, *ev->device, extract_as);
+    }
+    // ev->attr_value = 0; // Do not delete, python will.
+}
+
+
+void PyCallBackPushEvent::fill_py_event(Tango::AttrConfEventData* ev, object & py_ev, object py_device, PyTango::ExtractAs extract_as)
+{
+    copy_device(ev, py_ev, py_device);
+
+    if (ev->attr_conf) {
+        py_ev.attr("attr_conf") = *ev->attr_conf;
+    }
+}
+
+void PyCallBackPushEvent::fill_py_event(Tango::DataReadyEventData* ev, object & py_ev, object py_device, PyTango::ExtractAs extract_as)
+{
+    copy_device(ev, py_ev, py_device);
+}
+
+
+
+/*virtual*/ void PyCallBackPushEvent::push_event(Tango::EventData *ev)
+{
+    _push_event(this, ev);
+}
+
+/*virtual*/ void PyCallBackPushEvent::push_event(Tango::AttrConfEventData *ev)
+{
+    _push_event(this, ev);
+}
+
+/*virtual*/ void PyCallBackPushEvent::push_event(Tango::DataReadyEventData *ev)
+{
+    _push_event(this, ev);
+}
+
+void export_callback()
+{
+    PyCallBackAutoDie::init();
+
+    /// @todo move somewhere else, another file i tal...
+
+    class_<PyCmdDoneEvent> CmdDoneEvent("CmdDoneEvent", no_init);
+    CmdDoneEvent
+            .def_readonly("device", &PyCmdDoneEvent::device)
+            .def_readonly("cmd_name", &PyCmdDoneEvent::cmd_name)
+            .def_readonly("argout_raw", &PyCmdDoneEvent::argout_raw)
+            .def_readonly("argout", &PyCmdDoneEvent::argout)
+            .def_readonly("err", &PyCmdDoneEvent::err)
+            .def_readonly("errors", &PyCmdDoneEvent::errors)
+            .def_readonly("ext", &PyCmdDoneEvent::ext)
+    ;
+
+    class_<PyAttrReadEvent> AttrReadEvent("AttrReadEvent", no_init);
+    AttrReadEvent
+            .def_readonly("device", &PyAttrReadEvent::device)
+            .def_readonly("attr_names", &PyAttrReadEvent::attr_names)
+            .def_readonly("argout", &PyAttrReadEvent::argout)
+            .def_readonly("err", &PyAttrReadEvent::err)
+            .def_readonly("errors", &PyAttrReadEvent::errors)
+            .def_readonly("ext", &PyAttrReadEvent::ext)
+    ;
+
+    class_<PyAttrWrittenEvent> AttrWrittenEvent( "AttrWrittenEvent", no_init);
+    AttrWrittenEvent
+            .def_readonly("device", &PyAttrWrittenEvent::device)
+            .def_readonly("attr_names", &PyAttrWrittenEvent::attr_names)
+            .def_readonly("err", &PyAttrWrittenEvent::err)
+            .def_readonly("errors", &PyAttrWrittenEvent::errors)
+            .def_readonly("ext", &PyAttrWrittenEvent::ext)
+    ;
+
+    class_<PyCallBackAutoDie, boost::noncopyable> CallBackAutoDie(
+        "__CallBackAutoDie",
+        "INTERNAL CLASS - DO NOT USE IT",
+        init<>())
+    ;
+
+    CallBackAutoDie
+        .def("cmd_ended", &PyCallBackAutoDie::cmd_ended,
+            "This method is defined as being empty and must be overloaded by the user when the asynchronous callback model is used. This is the method which will be executed when the server reply from a command_inout is received in both push and pull sub-mode.")
+        .def("attr_read", &PyCallBackAutoDie::attr_read,
+            "This method is defined as being empty and must be overloaded by the user when the asynchronous callback model is used. This is the method which will be executed when the server reply from a read_attribute(s) is received in both push and pull sub-mode.")
+        .def("attr_written", &PyCallBackAutoDie::attr_written,
+            "This method is defined as being empty and must be overloaded by the user when the asynchronous callback model is used. This is the method which will be executed when the server reply from a write_attribute(s) is received in both push and pull sub-mode. ")
+    ;
+
+    class_<PyCallBackPushEvent, boost::noncopyable> CallBackPushEvent(
+        "__CallBackPushEvent",
+        "INTERNAL CLASS - DO NOT USE IT",
+        init<>())
+    ;
+
+    CallBackPushEvent
+        .def("push_event", (void (PyCallBackAutoDie::*)(Tango::EventData*))&PyCallBackAutoDie::push_event,
+            "This method is defined as being empty and must be overloaded by the user when events are used. This is the method which will be executed when the server send event(s) to the client. ")
+        .def("push_event", (void (PyCallBackAutoDie::*)(Tango::AttrConfEventData*))&PyCallBackAutoDie::push_event,
+            "This method is defined as being empty and must be overloaded by the user when events are used. This is the method which will be executed when the server send attribute configuration change event(s) to the client. ")
+        .def("push_event", (void (PyCallBackAutoDie::*)(Tango::DataReadyEventData*))&PyCallBackAutoDie::push_event,
+            "This method is defined as being empty and must be overloaded by the user when events are used. This is the method which will be executed when the server send attribute data ready event(s) to the client. ")
+    ;
+}
diff --git a/src/callback.h b/src/callback.h
new file mode 100644
index 0000000..50f3059
--- /dev/null
+++ b/src/callback.h
@@ -0,0 +1,106 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#pragma once
+
+#include <map>
+#include "defs.h"
+
+/// Tango expects an object for callbacks derived from Tango::CallBack.
+/// For read_attribute_asynch, write_attribute_asynch, the callback object
+/// should be available until the callback is run. Then it can disappear.
+/// Also if we forget about a DeviceProxy we don't need the callback anymore.
+/// For event subscription however, the requirements are different. The C++
+/// callback can be called way after the original DeviceProxy has disappered.
+/// So for this case, the callback should live forever. As we don't want it,
+/// we implemented the deletion of the callback in the DeviceProxy destructor
+/// itself, after performing an unsubscribe.
+/// @todo this is for cmd_ended, attr_read and attr_written. push_event are not done!
+class PyCallBackAutoDie : public Tango::CallBack , public boost::python::wrapper<Tango::CallBack>
+{
+public:
+    PyCallBackAutoDie() : m_self(0), m_weak_parent(0), m_extract_as(PyTango::ExtractAsNumpy) {}
+    virtual ~PyCallBackAutoDie();
+
+    //! It is the PyCallBackAutoDie object itself, as seen from python
+    PyObject* m_self;
+    //! The object that will call this callback, so we can
+    //! monitor if it disappears, we are not needed anymore.
+    PyObject* m_weak_parent;
+
+    PyTango::ExtractAs m_extract_as;
+
+    static std::map<PyObject*, PyObject*> s_weak2ob;
+    static boost::python::object py_on_callback_parent_fades;
+
+    static void on_callback_parent_fades(PyObject* weakobj);
+    static void init();
+
+    void set_autokill_references(boost::python::object &py_self, boost::python::object &py_parent);
+    void unset_autokill_references();
+
+    void set_extract_as(PyTango::ExtractAs extract_as)
+    {   this->m_extract_as = extract_as; }
+
+    boost::python::object get_override(const char* name)
+    { return boost::python::wrapper<Tango::CallBack>::get_override(name); }
+    
+    virtual void cmd_ended(Tango::CmdDoneEvent * ev);
+    virtual void attr_read(Tango::AttrReadEvent *ev);
+    virtual void attr_written(Tango::AttrWrittenEvent *ev);
+//     virtual void push_event(Tango::EventData *ev);
+//     virtual void push_event(Tango::AttrConfEventData *ev);
+//     virtual void push_event(Tango::DataReadyEventData *ev);
+};
+
+
+class PyCallBackPushEvent : public Tango::CallBack , public boost::python::wrapper<Tango::CallBack>
+{
+public:
+    PyCallBackPushEvent() : m_weak_device(0), m_extract_as(PyTango::ExtractAsNumpy) {}
+    virtual ~PyCallBackPushEvent();
+
+    //! The object that will call this callback (DeviceProxy), so we can
+    //! monitor if it disappears, we are not needed anymore.
+    PyObject* m_weak_device;
+    PyTango::ExtractAs m_extract_as;
+
+    void set_device(boost::python::object &py_device);
+
+    void set_extract_as(PyTango::ExtractAs extract_as)
+    {   this->m_extract_as = extract_as; }
+
+    boost::python::object get_override(const char* name)
+    { return boost::python::wrapper<Tango::CallBack>::get_override(name); }
+    
+//     virtual void cmd_ended(Tango::CmdDoneEvent * ev);
+//     virtual void attr_read(Tango::AttrReadEvent *ev);
+//     virtual void attr_written(Tango::AttrWrittenEvent *ev);
+    virtual void push_event(Tango::EventData *ev);
+    virtual void push_event(Tango::AttrConfEventData *ev);
+    virtual void push_event(Tango::DataReadyEventData *ev);
+
+    static void fill_py_event(Tango::EventData* ev, boost::python::object & py_ev, boost::python::object py_device, PyTango::ExtractAs extract_as);
+    static void fill_py_event(Tango::AttrConfEventData* ev, boost::python::object & py_ev, boost::python::object py_device, PyTango::ExtractAs extract_as);
+    static void fill_py_event(Tango::DataReadyEventData* ev, boost::python::object & py_ev, boost::python::object py_device, PyTango::ExtractAs extract_as);
+};
diff --git a/src/change_event_info.cpp b/src/change_event_info.cpp
new file mode 100644
index 0000000..dbdd364
--- /dev/null
+++ b/src/change_event_info.cpp
@@ -0,0 +1,36 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_change_event_info()
+{
+    class_<Tango::ChangeEventInfo>("ChangeEventInfo")
+        .def_readwrite("rel_change", &Tango::ChangeEventInfo::rel_change)
+        .def_readwrite("abs_change", &Tango::ChangeEventInfo::abs_change)
+        .def_readwrite("extensions", &Tango::ChangeEventInfo::extensions)
+    ;
+}
diff --git a/src/command_info.cpp b/src/command_info.cpp
new file mode 100644
index 0000000..7a0d64a
--- /dev/null
+++ b/src/command_info.cpp
@@ -0,0 +1,34 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_command_info()
+{
+    class_<Tango::CommandInfo , bases<Tango::DevCommandInfo> >("CommandInfo")
+        .def_readonly("disp_level", &Tango::CommandInfo::disp_level)
+        ;
+}
diff --git a/src/connection.cpp b/src/connection.cpp
new file mode 100644
index 0000000..18ae606
--- /dev/null
+++ b/src/connection.cpp
@@ -0,0 +1,196 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python/copy_const_reference.hpp>
+#include <boost/python/copy_non_const_reference.hpp>
+#include <tango.h>
+
+#include "pytgutils.h"
+#include "callback.h"
+
+namespace PyConnection
+{
+
+    using namespace boost::python;
+
+    static
+    Tango::DeviceData command_inout(Tango::Connection& self, const string & cmd_name, const Tango::DeviceData &argin)
+    {
+        AutoPythonAllowThreads guard;
+        return self.command_inout(const_cast<string&>(cmd_name), const_cast<Tango::DeviceData&>(argin));
+    }
+
+
+    static
+    long command_inout_asynch_id(Tango::Connection& self, const string &cmd_name, const Tango::DeviceData &argin, bool forget)
+    {
+        AutoPythonAllowThreads guard;
+        return self.command_inout_asynch(const_cast<string&>(cmd_name), const_cast<Tango::DeviceData&>(argin), forget);
+    }
+
+
+    static
+    Tango::DeviceData command_inout_reply(Tango::Connection& self, long id)
+    {
+        AutoPythonAllowThreads guard;
+        return self.command_inout_reply(id);
+    }
+
+    static
+    Tango::DeviceData command_inout_reply(Tango::Connection& self, long id, long timeout)
+    {
+        AutoPythonAllowThreads guard;
+        return self.command_inout_reply(id, timeout);
+    }
+
+    static
+    void command_inout_asynch_cb(object py_self, const string & cmd_name, const Tango::DeviceData &argin, object py_cb)
+    {
+        Tango::Connection* self = extract<Tango::Connection*>(py_self);
+        PyCallBackAutoDie* cb = extract<PyCallBackAutoDie*>(py_cb);
+        cb->set_autokill_references(py_cb, py_self);
+
+        try {
+            AutoPythonAllowThreads guard;
+            self->command_inout_asynch(const_cast<string&>(cmd_name), const_cast<Tango::DeviceData&>(argin), *cb);
+        } catch (...) {
+            cb->unset_autokill_references();
+            throw;
+        }
+    }
+
+    static
+    void get_asynch_replies(Tango::Connection& self)
+    {
+        AutoPythonAllowThreads guard;
+        self.get_asynch_replies();
+    }
+
+    static
+    void get_asynch_replies(Tango::Connection& self, long call_timeout)
+    {
+        AutoPythonAllowThreads guard;
+        self.get_asynch_replies(call_timeout);
+    }
+}
+
+void export_connection()
+{
+    using namespace boost::python;
+
+    class_<Tango::Connection, boost::noncopyable> Connection("Connection", no_init)
+    ;
+
+    Connection
+        .def("dev_name", pure_virtual(&Tango::Connection::dev_name))
+
+        .def("get_db_host", &Tango::Connection::get_db_host,
+            ( arg_("self") ),
+            return_value_policy<copy_non_const_reference>())
+
+        .def("get_db_port", &Tango::Connection::get_db_port,
+            ( arg_("self") ),
+            return_value_policy<copy_non_const_reference>())
+
+        .def("get_db_port_num", &Tango::Connection::get_db_port_num,
+            ( arg_("self") ))
+
+        .def("get_from_env_var", &Tango::Connection::get_from_env_var,
+            ( arg_("self") ))
+
+        .def("connect", &Tango::Connection::connect,
+            ( arg_("self"), arg_("corba_name") ))
+
+        .def("reconnect", &Tango::Connection::reconnect,
+            ( arg_("self"), arg_("db_used") ))
+
+        .def("get_idl_version", &Tango::Connection::get_idl_version,
+            ( arg_("self") ))
+
+        .def("set_timeout_millis", &Tango::Connection::set_timeout_millis,
+            ( arg_("self"), arg_("timeout") ))
+
+        .def("get_timeout_millis", &Tango::Connection::get_timeout_millis,
+            ( arg_("self") ))
+
+        .def("get_source", &Tango::Connection::get_source,
+            ( arg_("self") ))
+
+        .def("set_source", &Tango::Connection::set_source,
+            ( arg_("self"), arg_("source") ))
+
+        .def("get_transparency_reconnection",
+            &Tango::Connection::get_transparency_reconnection,
+            ( arg_("self") ))
+
+        .def("set_transparency_reconnection",
+            &Tango::Connection::set_transparency_reconnection,
+            ( arg_("self"), arg_("yesno") ))
+
+        .def("__command_inout", &PyConnection::command_inout)
+        .def("__command_inout_asynch_id", &PyConnection::command_inout_asynch_id)
+        .def("__command_inout_asynch_cb", &PyConnection::command_inout_asynch_cb)
+
+        .def("command_inout_reply_raw",
+            (Tango::DeviceData (*)(Tango::Connection&, long))
+            &PyConnection::command_inout_reply,
+            ( arg_("self"), arg_("id") ))
+
+        .def("command_inout_reply_raw",
+            (Tango::DeviceData (*)(Tango::Connection&, long, long))
+            &PyConnection::command_inout_reply,
+            ( arg_("self"), arg_("id"), arg_("timeout") ))
+
+
+        //
+        // Asynchronous methods
+        //
+
+        .def("get_asynch_replies",
+            (void (*) (Tango::Connection&))
+            &PyConnection::get_asynch_replies,
+            ( arg_("self") ))
+
+        .def("get_asynch_replies",
+            (void (*) (Tango::Connection&,long))
+            &PyConnection::get_asynch_replies,
+            ( arg_("self"), arg_("call_timeout") ))
+
+        .def("cancel_asynch_request",
+            &Tango::Connection::cancel_asynch_request,
+            ( arg_("self"), arg_("id") ))
+
+        .def("cancel_all_polling_asynch_request",
+            &Tango::Connection::cancel_all_polling_asynch_request,
+            ( arg_("self") ))
+
+        //
+        // Control access related methods
+        //
+        .def("get_access_control", &Tango::Connection::get_access_control,
+            ( arg_("self") ))
+
+        .def("set_access_control", &Tango::Connection::set_access_control,
+            ( arg_("self"), arg_("acc") ))
+    ;
+}
diff --git a/src/constants.cpp b/src/constants.cpp
new file mode 100644
index 0000000..638f909
--- /dev/null
+++ b/src/constants.cpp
@@ -0,0 +1,179 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_constants()
+{
+    object consts_module(handle<>(borrowed(PyImport_AddModule("PyTango.constants"))));
+    scope().attr("constants") = consts_module;
+    scope consts_scope = consts_module;
+    
+    consts_scope.attr("__doc__") = "module containing several Tango constants.\n"
+        "\nNew in PyTango 7.0.0";
+
+    //
+    // From tango_const.h
+    //
+
+    //
+    // Some general interest define
+    //
+
+    consts_scope.attr("TgLibVers") = TgLibVers;
+    consts_scope.attr("DevVersion") = DevVersion;
+    consts_scope.attr("DefaultMaxSeq") = DefaultMaxSeq;
+    consts_scope.attr("DefaultBlackBoxDepth") = DefaultBlackBoxDepth;
+    consts_scope.attr("DefaultPollRingDepth") = DefaultPollRingDepth;
+
+    consts_scope.attr("InitialOutput") = InitialOutput;
+    consts_scope.attr("DSDeviceDomain") = DSDeviceDomain;
+    consts_scope.attr("DefaultDocUrl") = DefaultDocUrl;
+    consts_scope.attr("EnvVariable") = EnvVariable;
+    consts_scope.attr("DbObjName") = DbObjName;
+    consts_scope.attr("DescNotSet") = DescNotSet;
+    consts_scope.attr("ResNotDefined") = ResNotDefined;
+    consts_scope.attr("MessBoxTitle") = MessBoxTitle;
+    consts_scope.attr("StatusNotSet") = StatusNotSet;
+
+    consts_scope.attr("DefaultWritAttrProp") = DefaultWritAttrProp;
+    consts_scope.attr("AllAttr") = AllAttr;
+    consts_scope.attr("AllAttr_3") = AllAttr_3;
+
+    consts_scope.attr("PollCommand") = PollCommand;
+    consts_scope.attr("PollAttribute") = PollAttribute;
+
+    consts_scope.attr("MIN_POLL_PERIOD") = MIN_POLL_PERIOD;
+    consts_scope.attr("DELTA_T") = DELTA_T;
+    consts_scope.attr("MIN_DELTA_WORK") = MIN_DELTA_WORK;
+    consts_scope.attr("TIME_HEARTBEAT") = TIME_HEARTBEAT;
+    consts_scope.attr("POLL_LOOP_NB") = POLL_LOOP_NB;
+    consts_scope.attr("ONE_SECOND") = ONE_SECOND;
+    consts_scope.attr("DISCARD_THRESHOLD") = DISCARD_THRESHOLD;
+
+    consts_scope.attr("DEFAULT_TIMEOUT") = DEFAULT_TIMEOUT;
+    consts_scope.attr("DEFAULT_POLL_OLD_FACTOR") = DEFAULT_POLL_OLD_FACTOR;
+
+    consts_scope.attr("TG_IMP_MINOR_TO") = TG_IMP_MINOR_TO;
+    consts_scope.attr("TG_IMP_MINOR_DEVFAILED") = TG_IMP_MINOR_DEVFAILED;
+    consts_scope.attr("TG_IMP_MINOR_NON_DEVFAILED") = TG_IMP_MINOR_NON_DEVFAILED;
+
+    consts_scope.attr("TANGO_PY_MOD_NAME") = TANGO_PY_MOD_NAME;
+    consts_scope.attr("DATABASE_CLASS") = DATABASE_CLASS;
+
+    //
+    // Event related define
+    //
+
+    consts_scope.attr("EVENT_HEARTBEAT_PERIOD") = EVENT_HEARTBEAT_PERIOD;
+    consts_scope.attr("EVENT_RESUBSCRIBE_PERIOD") = EVENT_RESUBSCRIBE_PERIOD;
+    consts_scope.attr("DEFAULT_EVENT_PERIOD") = DEFAULT_EVENT_PERIOD;
+    consts_scope.attr("DELTA_PERIODIC") = DELTA_PERIODIC;
+    consts_scope.attr("DELTA_PERIODIC_LONG") = DELTA_PERIODIC_LONG;
+    consts_scope.attr("HEARTBEAT") = HEARTBEAT;
+
+    //
+    // Locking feature related defines
+    //
+
+    consts_scope.attr("DEFAULT_LOCK_VALIDITY") = DEFAULT_LOCK_VALIDITY;
+    consts_scope.attr("DEVICE_UNLOCKED_REASON") = DEVICE_UNLOCKED_REASON;
+    consts_scope.attr("MIN_LOCK_VALIDITY") = MIN_LOCK_VALIDITY;
+
+    //
+    // Client timeout as defined by omniORB4.0.0
+    //
+
+    consts_scope.attr("CLNT_TIMEOUT_STR") = CLNT_TIMEOUT_STR;
+    consts_scope.attr("CLNT_TIMEOUT") = CLNT_TIMEOUT;
+
+    //
+    // Connection and call timeout for database device
+    //
+
+    consts_scope.attr("DB_CONNECT_TIMEOUT") = DB_CONNECT_TIMEOUT;
+    consts_scope.attr("DB_RECONNECT_TIMEOUT") = DB_RECONNECT_TIMEOUT;
+    consts_scope.attr("DB_TIMEOUT") = DB_TIMEOUT;
+    consts_scope.attr("DB_START_PHASE_RETRIES") = DB_START_PHASE_RETRIES;
+
+    //
+    // Time to wait before trying to reconnect after
+    // a connevtion failure
+    //
+    consts_scope.attr("RECONNECTION_DELAY") = RECONNECTION_DELAY;
+
+    //
+    // Access Control related defines
+    // WARNING: these string are also used within the Db stored procedure
+    // introduced in Tango V6.1. If you chang eit here, don't forget to
+    // also update the stored procedure
+    //
+
+    consts_scope.attr("CONTROL_SYSTEM") = CONTROL_SYSTEM;
+    consts_scope.attr("SERVICE_PROP_NAME") = SERVICE_PROP_NAME;
+    consts_scope.attr("ACCESS_SERVICE") = ACCESS_SERVICE;
+
+    //
+    // Polling threads pool related defines
+    //
+
+    consts_scope.attr("DEFAULT_POLLING_THREADS_POOL_SIZE") = DEFAULT_POLLING_THREADS_POOL_SIZE;
+
+    //
+    // Max transfer size 256 MBytes (in byte). Needed by omniORB
+    //
+
+    consts_scope.attr("MAX_TRANSFER_SIZE") = MAX_TRANSFER_SIZE;
+
+    //
+    // Tango name length
+    //
+
+    consts_scope.attr("MaxServerNameLength") = MaxServerNameLength;
+
+    //
+    // Files used to retrieve env. variables
+    //
+
+    consts_scope.attr("USER_ENV_VAR_FILE") = USER_ENV_VAR_FILE;
+
+    consts_scope.attr("kLogTargetConsole") = kLogTargetConsole;
+    consts_scope.attr("kLogTargetFile") = kLogTargetFile;
+    consts_scope.attr("kLogTargetDevice") = kLogTargetDevice;
+    consts_scope.attr("kLogTargetSep") = kLogTargetSep;
+    
+    consts_scope.attr("AlrmValueNotSpec") = AlrmValueNotSpec;
+    consts_scope.attr("AssocWritNotSpec") = AssocWritNotSpec;
+    consts_scope.attr("LabelNotSpec") = LabelNotSpec;
+    consts_scope.attr("DescNotSpec") = DescNotSpec;
+    consts_scope.attr("UnitNotSpec") = UnitNotSpec;
+    consts_scope.attr("StdUnitNotSpec") = StdUnitNotSpec;
+    consts_scope.attr("DispUnitNotSpec") = DispUnitNotSpec;
+    consts_scope.attr("FormatNotSpec") = FormatNotSpec;
+    consts_scope.attr("NotANumber") = NotANumber;
+    consts_scope.attr("MemNotUsed") = MemNotUsed;
+    consts_scope.attr("MemAttrPropName") = MemAttrPropName;
+}
diff --git a/src/data_ready_event_data.cpp b/src/data_ready_event_data.cpp
new file mode 100644
index 0000000..a45cce3
--- /dev/null
+++ b/src/data_ready_event_data.cpp
@@ -0,0 +1,60 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+struct PyDataReadyEventData
+{
+    static inline Tango::DeviceProxy* get_device(Tango::DataReadyEventData &self)
+    {
+        return self.device;
+    }
+};
+
+void export_data_ready_event_data()
+{
+    class_<Tango::DataReadyEventData>("DataReadyEventData",
+        init<const Tango::DataReadyEventData &>())
+
+        // The original Tango::EventData structure has a 'device' field.
+        // However, if we returned this directly we would get a different
+        // python device each time. So we are doing our weird things to make
+        // sure the device returned is the same where the read action was
+        // performed. So we don't return Tango::EventData::device directly.
+        // See callback.cpp
+        .setattr("device",object())
+        .def_readonly("attr_name", &Tango::DataReadyEventData::attr_name)
+        .def_readonly("event", &Tango::DataReadyEventData::event)
+        .def_readonly("attr_data_type", &Tango::DataReadyEventData::attr_data_type)
+        .def_readonly("ctr", &Tango::DataReadyEventData::ctr)
+        .def_readonly("err", &Tango::DataReadyEventData::err)
+        .def_readonly("reception_date", &Tango::DataReadyEventData::reception_date)
+        .add_property("errors", make_getter(&Tango::DataReadyEventData::errors, 
+            return_value_policy<copy_non_const_reference>()))
+        .def("get_date", &Tango::DataReadyEventData::get_date,
+            return_internal_reference<>())
+    ;
+}
diff --git a/src/database.cpp b/src/database.cpp
new file mode 100644
index 0000000..bb4868d
--- /dev/null
+++ b/src/database.cpp
@@ -0,0 +1,457 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <boost/python/return_value_policy.hpp>
+#include <tango.h>
+#include <string>
+
+#include "defs.h"
+#include "pytgutils.h"
+
+using namespace boost::python;
+
+extern const char *param_must_be_seq;
+extern const char *unreachable_code;
+extern const char *non_string_seq;
+
+const char *param_numb_or_str_numb = "Second parameter must be an int or a "
+                                     "string representing an int";
+
+struct PyDatabase
+{
+    struct PickleSuite : pickle_suite
+    {
+        static tuple getinitargs(Tango::Database& self)
+        {
+            std::string& host = self.get_db_host();
+            std::string& port = self.get_db_port();
+            if (host.size() > 0 && port.size() > 0)
+            {
+                return make_tuple(host, port);
+            }
+            else
+                return make_tuple();
+        }
+    };
+    
+    static inline boost::shared_ptr<Tango::Database>
+    makeDatabase_host_port1(const std::string &host, int port)
+    {
+        return boost::shared_ptr<Tango::Database>
+            (new Tango::Database(const_cast<std::string&>(host), port));
+    }
+
+    static inline boost::shared_ptr<Tango::Database>
+    makeDatabase_host_port2(const std::string &host, const std::string &port_str)
+    {
+        std::istringstream port_stream(port_str);
+        int port = 0;
+        if(!(port_stream >> port))
+        {
+            raise_(PyExc_TypeError, param_numb_or_str_numb);
+        }
+        return boost::shared_ptr<Tango::Database>
+            (new Tango::Database(const_cast<std::string&>(host), port));
+    }
+
+    static inline boost::shared_ptr<Tango::Database>
+    makeDatabase_file(const std::string &filename)
+    {
+        return boost::shared_ptr<Tango::Database>
+            (new Tango::Database(const_cast<std::string&>(filename)));
+    }
+
+    static inline boost::python::str
+    get_device_alias(Tango::Database& self, const std::string &alias)
+    {
+        std::string devname;
+        self.get_device_alias(alias, devname);
+        return boost::python::str(devname);
+    }
+
+    static inline boost::python::str
+    get_alias(Tango::Database& self, const std::string &devname)
+    {
+        std::string alias;
+        self.get_alias(devname, alias);
+        return boost::python::str(alias);
+    }
+
+    static inline void
+    get_device_property_list2(Tango::Database& self, const std::string &devname,
+                              const std::string &wildcard, StdStringVector &d)
+    {
+        self.get_device_property_list(const_cast<std::string&>(devname), wildcard, d);
+    }
+
+    static inline boost::python::str
+    get_attribute_alias(Tango::Database& self, const std::string &alias)
+    {
+        std::string attrname;
+        self.get_attribute_alias(alias, attrname);
+        return boost::python::str(attrname);
+    }
+
+    static inline void
+    export_event(Tango::Database& self, const boost::python::object &obj)
+    {
+        Tango::DevVarStringArray par;
+        convert2array(obj, par);
+        self.export_event(&par);
+    }
+
+    static inline boost::python::str dev_name(Tango::Database& self)
+    {
+        Tango::Connection *conn = static_cast<Tango::Connection *>(&self);
+        return boost::python::str(conn->dev_name());
+    }
+};
+
+void export_database()
+{
+    // The following function declarations are necessary to be able to cast
+    // the function parameters from string& to const string&, otherwise python
+    // will not recognize the method calls
+
+    Tango::DbDatum (Tango::Database::*get_host_list_)(std::string &) =
+        &Tango::Database::get_host_list;
+    Tango::DbDatum (Tango::Database::*get_services_)(std::string &, std::string &) =
+        &Tango::Database::get_services;
+    void (Tango::Database::*register_service_)(std::string &, std::string &, std::string &) =
+        &Tango::Database::register_service;
+    void (Tango::Database::*unregister_service_)(std::string &, std::string &) =
+        &Tango::Database::unregister_service;
+    Tango::DbDatum (Tango::Database::*get_device_name_)(std::string &, std::string &) =
+        &Tango::Database::get_device_name;
+    Tango::DbDatum (Tango::Database::*get_device_exported_)(std::string &) =
+        &Tango::Database::get_device_exported;
+    Tango::DbDatum (Tango::Database::*get_device_domain_)(std::string &) =
+        &Tango::Database::get_device_domain;
+    Tango::DbDatum (Tango::Database::*get_device_family_)(std::string &) =
+        &Tango::Database::get_device_family;
+    Tango::DbDatum (Tango::Database::*get_device_member_)(std::string &) =
+        &Tango::Database::get_device_member;
+    Tango::DbDatum (Tango::Database::*get_device_alias_list_)(std::string &) =
+        &Tango::Database::get_device_alias_list;
+    std::string (Tango::Database::*get_class_for_device_)(std::string &) =
+        &Tango::Database::get_class_for_device;
+    Tango::DbDatum (Tango::Database::*get_class_inheritance_for_device_)(std::string &) =
+        &Tango::Database::get_class_inheritance_for_device;
+    Tango::DbDatum (Tango::Database::*get_device_exported_for_class_)(std::string &) =
+        &Tango::Database::get_device_exported_for_class;
+    void (Tango::Database::*put_device_alias_)(std::string &, std::string &) =
+        &Tango::Database::put_device_alias;
+    void (Tango::Database::*delete_device_alias_)(std::string &) =
+        &Tango::Database::delete_device_alias;
+    void (Tango::Database::*add_server_)(std::string &, Tango::DbDevInfos &) =
+        &Tango::Database::add_server;
+    void (Tango::Database::*delete_server_)(std::string &) =
+        &Tango::Database::delete_server;
+    void (Tango::Database::*unexport_server_)(std::string &) =
+        &Tango::Database::unexport_server;
+    Tango::DbServerInfo (Tango::Database::*get_server_info_)(std::string &) =
+        &Tango::Database::get_server_info;
+    void (Tango::Database::*delete_server_info_)(std::string &) =
+        &Tango::Database::delete_server_info;
+    Tango::DbDatum (Tango::Database::*get_server_class_list_)(std::string &) =
+        &Tango::Database::get_server_class_list;
+    Tango::DbDatum (Tango::Database::*get_instance_name_list_)(std::string &) =
+        &Tango::Database::get_instance_name_list;
+    Tango::DbDatum (Tango::Database::*get_server_list_)(std::string &) =
+        &Tango::Database::get_server_list;
+    Tango::DbDatum (Tango::Database::*get_host_server_list_)(std::string &) =
+        &Tango::Database::get_host_server_list;
+    Tango::DbDatum (Tango::Database::*get_device_class_list_)(std::string &) =
+        &Tango::Database::get_device_class_list;
+    Tango::DbHistoryList (Tango::Database::*get_property_history_)(std::string &, std::string &) =
+        &Tango::Database::get_property_history;
+    Tango::DbDatum (Tango::Database::*get_object_list_)(std::string &) =
+        &Tango::Database::get_object_list;
+    Tango::DbDatum (Tango::Database::*get_object_property_list_)(std::string &, std::string &) =
+        &Tango::Database::get_object_property_list;
+    Tango::DbHistoryList (Tango::Database::*get_device_property_history_)(std::string &, std::string &) =
+        &Tango::Database::get_device_property_history;
+    Tango::DbDatum (Tango::Database::*get_device_property_list1_)(std::string &, std::string &) =
+        &Tango::Database::get_device_property_list;
+    Tango::DbHistoryList (Tango::Database::*get_device_attribute_property_history_)(std::string &, std::string &, std::string &) =
+        &Tango::Database::get_device_attribute_property_history;
+    Tango::DbHistoryList (Tango::Database::*get_class_property_history_)(std::string &, std::string &) =
+        &Tango::Database::get_class_property_history;
+    Tango::DbDatum (Tango::Database::*get_class_list_)(std::string &) =
+        &Tango::Database::get_class_list;
+    Tango::DbDatum (Tango::Database::*get_class_property_list_)(std::string &) =
+        &Tango::Database::get_class_property_list;
+    Tango::DbHistoryList (Tango::Database::*get_class_attribute_property_history_)(std::string &, std::string &, std::string &) =
+        &Tango::Database::get_class_attribute_property_history;
+    Tango::DbDatum (Tango::Database::*get_class_attribute_list_)(std::string &, std::string &) =
+        &Tango::Database::get_class_attribute_list;
+
+    Tango::DbDevImportInfo (Tango::Database::*import_device_)(std::string &) =
+        &Tango::Database::import_device;
+    
+    Tango::DbDatum (Tango::Database::*get_attribute_alias_list_)(std::string &) =
+        &Tango::Database::get_attribute_alias_list;
+    void (Tango::Database::*put_attribute_alias_)(std::string &, std::string &) =
+        &Tango::Database::put_attribute_alias;
+    void (Tango::Database::*delete_attribute_alias_)(std::string &) =
+        &Tango::Database::delete_attribute_alias;
+    
+    
+    class_<Tango::Database, bases<Tango::Connection> > Database(
+        "Database",
+        init<>())
+    ;
+
+    Database
+        .def("__init__", make_constructor(PyDatabase::makeDatabase_host_port1))
+        .def("__init__", make_constructor(PyDatabase::makeDatabase_host_port2))
+        .def("__init__", make_constructor(PyDatabase::makeDatabase_file))
+
+        //
+        // Pickle
+        //
+        .def_pickle(PyDatabase::PickleSuite())
+        
+        //
+        // general methods
+        //
+        .def("dev_name", &PyDatabase::dev_name)
+        .def("write_filedatabase", &Tango::Database::write_filedatabase)
+        .def("reread_filedatabase", &Tango::Database::write_filedatabase)
+        .def("build_connection", &Tango::Database::write_filedatabase)
+        .def("check_tango_host", &Tango::Database::check_tango_host)
+        .def("check_access_control", &Tango::Database::check_access_control)
+        .def("is_control_access_checked",
+            &Tango::Database::is_control_access_checked)
+        .def("set_access_checked",
+            &Tango::Database::set_access_checked)
+        .def("get_access_except_errors",
+            &Tango::Database::get_access_except_errors,
+            return_internal_reference<1>())
+
+        //
+        // General methods
+        //
+
+        .def("get_info",&Tango::Database::get_info)
+        .def("get_host_list",
+            (Tango::DbDatum (Tango::Database::*) ())
+            &Tango::Database::get_host_list)
+        .def("get_host_list",
+            (Tango::DbDatum (Tango::Database::*) (const std::string &))
+            get_host_list_)
+        .def("get_services",
+            (Tango::DbDatum (Tango::Database::*) (const std::string &, const std::string &))
+            get_services_)
+        .def("register_service",
+            (void (Tango::Database::*) (const std::string &, const std::string &, const std::string &))
+            register_service_)
+        .def("unregister_service",
+            (void (Tango::Database::*) (const std::string &, const std::string &))
+            unregister_service_)
+
+        //
+        // Device methods
+        //
+
+        .def("add_device", &Tango::Database::add_device)
+        .def("delete_device", &Tango::Database::delete_device)
+        .def("import_device", (Tango::DbDevImportInfo (Tango::Database::*) (const std::string &))
+        import_device_)
+        .def("export_device", &Tango::Database::export_device)
+        .def("unexport_device", &Tango::Database::unexport_device)
+        .def("get_device_name",
+            (Tango::DbDatum (Tango::Database::*) (const string &, const string &))
+            get_device_name_)
+        .def("get_device_exported",
+            (Tango::DbDatum (Tango::Database::*) (const string &))
+            get_device_exported_)
+        .def("get_device_domain",
+            (Tango::DbDatum (Tango::Database::*) (const string &))
+            get_device_domain_)
+        .def("get_device_family",
+            (Tango::DbDatum (Tango::Database::*) (const string &))
+            get_device_family_)
+        .def("get_device_member",
+            (Tango::DbDatum (Tango::Database::*) (const string &))
+            get_device_member_)
+        .def("get_device_alias", &PyDatabase::get_device_alias)
+        .def("get_alias", &PyDatabase::get_alias)
+        .def("get_device_alias_list",
+            (Tango::DbDatum (Tango::Database::*) (const std::string &))
+            get_device_alias_list_)
+        .def("get_class_for_device",
+            (std::string (Tango::Database::*) (const std::string &))
+            get_class_for_device_)
+        .def("get_class_inheritance_for_device",
+            (Tango::DbDatum (Tango::Database::*) (const std::string &))
+            get_class_inheritance_for_device_)
+        .def("get_device_exported_for_class",
+            (Tango::DbDatum (Tango::Database::*) (const std::string &))
+            get_device_exported_for_class_)
+        .def("put_device_alias",
+            (void (Tango::Database::*) (const std::string &, const std::string &))
+            put_device_alias_)
+        .def("delete_device_alias",
+            (void (Tango::Database::*) (const std::string &))
+            delete_device_alias_)
+
+        //
+        // server methods
+        //
+
+        .def("_add_server",
+            (void (Tango::Database::*) (const std::string &, Tango::DbDevInfos &))
+            add_server_)
+        .def("delete_server",
+            (void (Tango::Database::*) (const std::string &))
+            delete_server_)
+        .def("_export_server", &Tango::Database::export_server)
+        .def("unexport_server",
+            (void (Tango::Database::*) (const std::string &))
+            unexport_server_)
+        .def("get_server_info",
+            (Tango::DbServerInfo (Tango::Database::*) (const std::string &))
+            get_server_info_)
+        .def("put_server_info", &Tango::Database::put_server_info,
+            ( arg_("self"), arg_("info") ))
+        .def("delete_server_info",
+            (void (Tango::Database::*) (const std::string &))
+            delete_server_info_)
+        .def("get_server_class_list",
+            (Tango::DbDatum (Tango::Database::*) (const std::string &))
+            get_server_class_list_)
+        .def("get_server_name_list", &Tango::Database::get_server_name_list)
+        .def("get_instance_name_list",
+            (Tango::DbDatum (Tango::Database::*) (const std::string &))
+            get_instance_name_list_)
+        .def("get_server_list",
+            (Tango::DbDatum (Tango::Database::*) ())
+            &Tango::Database::get_server_list)
+        .def("get_server_list",
+            (Tango::DbDatum (Tango::Database::*) (const std::string &))
+            get_server_list_)
+        .def("get_host_server_list",
+            (Tango::DbDatum (Tango::Database::*) (const std::string &))
+            get_host_server_list_)
+        .def("get_device_class_list",
+            (Tango::DbDatum (Tango::Database::*) (const std::string &))
+            get_device_class_list_)
+
+        //
+        // property methods
+        //
+
+        .def("_get_property",
+            (void (Tango::Database::*) (std::string, Tango::DbData &))
+            &Tango::Database::get_property)
+        .def("_get_property_forced", &Tango::Database::get_property_forced)
+        .def("_put_property", &Tango::Database::put_property)
+        .def("_delete_property", &Tango::Database::delete_property)
+        .def("get_property_history",
+            (Tango::DbHistoryList (Tango::Database::*) (const std::string &, const std::string &))
+            get_property_history_)
+        .def("get_object_list",
+            (Tango::DbDatum (Tango::Database::*) (const std::string &))
+            get_object_list_)
+        .def("get_object_property_list",
+            (Tango::DbDatum (Tango::Database::*) (const std::string &, const std::string &))
+            get_object_property_list_)
+        .def("_get_device_property",
+            (void (Tango::Database::*) (std::string, Tango::DbData &))
+            &Tango::Database::get_device_property)
+        .def("_put_device_property", &Tango::Database::put_device_property)
+        .def("_delete_device_property", &Tango::Database::delete_device_property)
+        .def("get_device_property_history",
+            (Tango::DbHistoryList (Tango::Database::*) (const std::string &, const std::string &))
+            get_device_property_history_)
+        .def("_get_device_property_list",
+            (Tango::DbDatum (Tango::Database::*) (const std::string &, const std::string &))
+            get_device_property_list1_)
+        .def("_get_device_property_list", &PyDatabase::get_device_property_list2)
+        .def("_get_device_attribute_property",
+            (void (Tango::Database::*) (std::string, Tango::DbData &))
+            &Tango::Database::get_device_attribute_property)
+        .def("_put_device_attribute_property",
+            &Tango::Database::put_device_attribute_property)
+        .def("_delete_device_attribute_property",
+            &Tango::Database::delete_device_attribute_property)
+        .def("get_device_attribute_property_history",
+            (Tango::DbHistoryList (Tango::Database::*) (const std::string &, const std::string &, const std::string &))
+            get_device_attribute_property_history_)
+        .def("_get_class_property",
+            (void (Tango::Database::*) (std::string, Tango::DbData &))
+            &Tango::Database::get_class_property)
+        .def("_put_class_property", &Tango::Database::put_class_property)
+        .def("_delete_class_property", &Tango::Database::delete_class_property)
+        .def("get_class_property_history",
+            (Tango::DbHistoryList (Tango::Database::*) (const std::string &, const std::string &))
+            get_class_property_history_)
+        .def("get_class_list",
+            (Tango::DbDatum (Tango::Database::*) (const std::string &))
+            get_class_list_)
+        .def("get_class_property_list",
+            (Tango::DbDatum (Tango::Database::*) (const std::string &))
+            get_class_property_list_)
+        .def("_get_class_attribute_property",
+            (void (Tango::Database::*) (std::string, Tango::DbData &))
+            &Tango::Database::get_class_attribute_property)
+        .def("_put_class_attribute_property",
+            &Tango::Database::put_class_attribute_property)
+        .def("_delete_class_attribute_property",
+            &Tango::Database::delete_class_attribute_property)
+        .def("get_class_attribute_property_history",
+            (Tango::DbHistoryList (Tango::Database::*) (const std::string &, const std::string &, const std::string &))
+            get_class_attribute_property_history_)
+
+        .def("get_class_attribute_list",
+            (Tango::DbDatum (Tango::Database::*) (const std::string &, const std::string &))
+            get_class_attribute_list_)
+
+        //
+        // Attribute methods
+        //
+
+        .def("get_attribute_alias", &PyDatabase::get_attribute_alias)
+        .def("get_attribute_alias_list",
+            (Tango::DbDatum (Tango::Database::*) (const std::string &))
+            get_attribute_alias_list_)
+        .def("put_attribute_alias",
+            (void (Tango::Database::*) (const std::string &, const std::string &))
+            put_attribute_alias_)
+        .def("delete_attribute_alias",
+            (void (Tango::Database::*) (const std::string &))
+            delete_attribute_alias_)
+
+        //
+        // event methods
+        //
+
+        .def("export_event", &PyDatabase::export_event)
+        .def("unexport_event",
+            (void (Tango::Database::*) (const std::string &))
+            &Tango::Database::unexport_event)
+        ;
+}
+
diff --git a/src/db.cpp b/src/db.cpp
new file mode 100644
index 0000000..ca7589d
--- /dev/null
+++ b/src/db.cpp
@@ -0,0 +1,90 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+#include "defs.h"
+#include "pytgutils.h"
+
+using namespace boost::python;
+
+void export_database();
+
+void export_db()
+{
+    // Note: DbDatum in python is extended to support the python sequence API
+    //       in the file ../PyTango/db.py. This way the DbDatum behaves like a
+    //       sequence of strings. This allows the user to work with a DbDatum as
+    //       if it was working with the old list of strings
+
+    class_<Tango::DbDatum>("DbDatum", init<>())
+        .def(init<const char *>())
+        .def(init<const Tango::DbDatum &>())
+        .def_readwrite("name", &Tango::DbDatum::name)
+        .def_readwrite("value_string", &Tango::DbDatum::value_string)
+        .def("size", &Tango::DbDatum::size)
+        .def("is_empty", &Tango::DbDatum::is_empty)
+    ;
+
+    class_<Tango::DbDevExportInfo>("DbDevExportInfo")
+        .def_readwrite("name", &Tango::DbDevExportInfo::name)
+        .def_readwrite("ior", &Tango::DbDevExportInfo::ior)
+        .def_readwrite("host", &Tango::DbDevExportInfo::host)
+        .def_readwrite("version", &Tango::DbDevExportInfo::version)
+        .def_readwrite("pid", &Tango::DbDevExportInfo::pid)
+    ;
+
+     class_<Tango::DbDevImportInfo>("DbDevImportInfo")
+        .def_readonly("name", &Tango::DbDevImportInfo::name)
+        .def_readonly("exported", &Tango::DbDevImportInfo::exported)
+        .def_readonly("ior", &Tango::DbDevImportInfo::ior)
+        .def_readonly("version", &Tango::DbDevImportInfo::version)
+    ;
+
+     class_<Tango::DbDevInfo>("DbDevInfo")
+        .def_readwrite("name", &Tango::DbDevInfo::name)
+        .def_readwrite("_class", &Tango::DbDevInfo::_class)
+        .def_readwrite("klass", &Tango::DbDevInfo::_class)
+        .def_readwrite("server", &Tango::DbDevInfo::server)
+    ;
+
+    class_<Tango::DbHistory>("DbHistory",
+        init<std::string, std::string, StdStringVector &>())
+        .def(init<std::string, std::string, std::string, StdStringVector &>())
+        .def("get_name", &Tango::DbHistory::get_name)
+        .def("get_attribute_name", &Tango::DbHistory::get_attribute_name)
+        .def("get_date", &Tango::DbHistory::get_date)
+        .def("get_value", &Tango::DbHistory::get_value)
+        .def("is_deleted", &Tango::DbHistory::is_deleted)
+    ;
+
+    class_<Tango::DbServerInfo>("DbServerInfo")
+         .def_readwrite("name", &Tango::DbServerInfo::name)
+         .def_readwrite("host", &Tango::DbServerInfo::host)
+         .def_readwrite("mode", &Tango::DbServerInfo::mode)
+         .def_readwrite("level", &Tango::DbServerInfo::level)
+    ;
+
+    export_database();
+}
diff --git a/src/defs.h b/src/defs.h
new file mode 100644
index 0000000..53408c5
--- /dev/null
+++ b/src/defs.h
@@ -0,0 +1,43 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+typedef std::vector<std::string> StdStringVector;
+typedef std::vector<long> StdLongVector;
+typedef std::vector<double> StdDoubleVector;
+
+namespace PyTango
+{
+    enum ExtractAs {
+        ExtractAsNumpy,
+        ExtractAsTuple,
+        ExtractAsList,
+        ExtractAsString,
+        ExtractAsPyTango3,
+        ExtractAsNothing
+    };
+}
diff --git a/src/dev_command_info.cpp b/src/dev_command_info.cpp
new file mode 100644
index 0000000..b34735f
--- /dev/null
+++ b/src/dev_command_info.cpp
@@ -0,0 +1,43 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_dev_command_info()
+{
+    typedef Tango::CmdArgType Tango::_DevCommandInfo::* MemCmdArgType;
+
+    class_<Tango::DevCommandInfo>("DevCommandInfo")
+        .def_readonly("cmd_name", &Tango::DevCommandInfo::cmd_name)
+        .def_readonly("cmd_tag", &Tango::DevCommandInfo::cmd_tag)
+        .def_readonly("in_type",
+                reinterpret_cast<MemCmdArgType>(&Tango::DevCommandInfo::in_type))
+        .def_readonly("out_type",
+                reinterpret_cast<MemCmdArgType>(&Tango::DevCommandInfo::out_type))
+        .def_readonly("in_type_desc", &Tango::DevCommandInfo::in_type_desc)
+        .def_readonly("out_type_desc", &Tango::DevCommandInfo::out_type_desc)
+    ;
+}
diff --git a/src/dev_error.cpp b/src/dev_error.cpp
new file mode 100644
index 0000000..50946aa
--- /dev/null
+++ b/src/dev_error.cpp
@@ -0,0 +1,50 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+struct PyDevError
+{
+    static inline PyObject* get_reason(Tango::DevError &de)
+    { return PyString_FromString(de.reason); }
+
+    static inline PyObject* get_desc(Tango::DevError &de)
+    { return PyString_FromString(de.desc); }
+
+    static inline PyObject* get_origin(Tango::DevError &de)
+    { return PyString_FromString(de.origin); }
+
+};
+
+void export_dev_error()
+{
+    class_<Tango::DevError>("DevError")
+        .add_property("reason", &PyDevError::get_reason)
+        .def_readonly("severity", &Tango::DevError::severity)
+        .add_property("desc", &PyDevError::get_desc)
+        .add_property("origin", &PyDevError::get_origin)
+    ;
+}
diff --git a/src/device_attribute.cpp b/src/device_attribute.cpp
new file mode 100644
index 0000000..5e3ecc3
--- /dev/null
+++ b/src/device_attribute.cpp
@@ -0,0 +1,656 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+#include <iostream>
+#include <string>
+#include <memory>
+
+#include "device_attribute.h"
+
+#include "pytgutils.h"
+#include "tango_numpy.h"
+#include "fast_from_py.h"
+
+using namespace boost::python;
+
+extern const char *non_valid_image;
+extern const char *non_valid_spectrum;
+
+// Why am I storing 'type' as a python attribute with object::attr
+// instead of as a property calling DeviceAttribute::get_type here?
+// Because after 'extract'ing, any call to get_type() will fail. Same
+// for "value" and "w_value". And for has_failed and is_empty...
+static const char* value_attr_name = "value";
+static const char* w_value_attr_name = "w_value";
+static const char* type_attr_name = "type";
+static const char* is_empty_attr_name = "is_empty";
+static const char* has_failed_attr_name = "has_failed";
+
+
+template<long tangoTypeConst>
+struct python_tangocpp {
+    typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+
+    static inline void to_cpp(const object & py_value, TangoScalarType & result)
+    {
+        result = extract<TangoScalarType>(py_value);
+    }
+
+    static inline object to_python(const TangoScalarType & value)
+    {
+        return object(value);
+    }
+};
+
+template<>
+struct python_tangocpp<Tango::DEV_STRING> {
+    static const long tangoTypeConst = Tango::DEV_STRING;
+    typedef TANGO_const2type(tangoTypeConst) TangoScalarType;
+
+    static inline void to_cpp(const object & py_value, TangoScalarType & result)
+    {
+        result = CORBA::string_dup(extract<TangoScalarType>(py_value));
+    }
+
+    static inline object to_python(const TangoScalarType & value)
+    {
+        return object(std::string(value));
+    }
+};
+
+#ifndef DISABLE_PYTANGO_NUMPY
+#   include "device_attribute_numpy.hpp"
+#endif
+
+namespace PyDeviceAttribute {
+
+    template<long tangoTypeConst>
+    static inline void _update_scalar_values(Tango::DeviceAttribute &self, object py_value)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+
+        if (self.get_written_dim_x() > 0) {
+            std::vector<TangoScalarType> val;
+            self >> val;
+            // In the following lines, the cast is absolutely necessary because
+            // vector<TangoScalarType> may not be a vector<TangoScalarType> at
+            // compile time. For example, for vector<DevBoolean>, the compiler
+            // may create a std::_Bit_reference type.
+            py_value.attr(value_attr_name) = object((TangoScalarType)val[0]);
+            py_value.attr(w_value_attr_name) = object((TangoScalarType)val[1]);
+        } else {
+            TangoScalarType rvalue;
+            self >> rvalue;
+            py_value.attr(value_attr_name) = object(rvalue);
+            py_value.attr(w_value_attr_name) = object();
+        }
+    }
+
+    template<>
+    inline void _update_scalar_values<Tango::DEV_ENCODED>(Tango::DeviceAttribute &self, object py_value)
+    {
+        Tango::DevVarEncodedArray* value;
+        self >> value;
+        std::auto_ptr<Tango::DevVarEncodedArray> guard(value);
+
+        Tango::DevEncoded* buffer = value->get_buffer();
+
+        /// @todo I am making a copy of encoded_data as string. This
+        /// is far from ideal, but it's what we have now...
+        using namespace boost::python;
+        if (self.get_written_dim_x() > 0) {
+            str encoded_format(buffer[0].encoded_format);
+            str w_encoded_format(buffer[1].encoded_format);
+
+            str encoded_data((const char*)buffer[0].encoded_data.get_buffer(), buffer[0].encoded_data.length());
+            str w_encoded_data((const char*)buffer[1].encoded_data.get_buffer(), buffer[1].encoded_data.length());
+
+            py_value.attr(value_attr_name) = make_tuple(encoded_format, encoded_data);
+            py_value.attr(w_value_attr_name) = make_tuple(w_encoded_format, w_encoded_data);
+        } else {
+            str encoded_format(buffer[0].encoded_format);
+            str encoded_data((const char*)buffer[0].encoded_data.get_buffer(), buffer[0].encoded_data.length());
+            
+            py_value.attr(value_attr_name) = make_tuple(encoded_format, encoded_data);
+            py_value.attr(w_value_attr_name) = object();
+        }
+    }
+
+    template<>
+    inline void _update_scalar_values<Tango::DEV_STRING>(Tango::DeviceAttribute &self, object py_value)
+    {
+        if (self.get_written_dim_x() > 0) { /// @todo not the same as old pytango, 'writable' missing...
+            std::vector<std::string> val;
+            self >> val;
+
+            py_value.attr(value_attr_name) = object(val[0]);
+            py_value.attr(w_value_attr_name) = object(val[1]);
+        } else {
+            std::string rvalue;
+            self >> rvalue;
+
+            py_value.attr(value_attr_name) = object(rvalue);
+            py_value.attr(w_value_attr_name) = object();
+        }
+    }
+
+    template<long tangoTypeConst>
+    static inline void _update_array_values_as_lists(Tango::DeviceAttribute &self, bool isImage, object py_value)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+        typedef typename TANGO_const2arraytype(tangoTypeConst) TangoArrayType;
+
+        // Extract the actual data from Tango::DeviceAttribute (self)
+        TangoArrayType* value_ptr = 0;
+        try {
+            self >> value_ptr;
+        } catch (Tango::DevFailed &e ) {
+            if (strcmp(e.errors[0].reason.in(),"API_EmptyDeviceAttribute") != 0)
+                throw;
+        }
+        std::auto_ptr<TangoArrayType> guard_value_ptr(value_ptr);
+
+        if (value_ptr == 0) {
+            // Empty device attribute
+            py_value.attr(value_attr_name) = boost::python::list();
+            py_value.attr(w_value_attr_name) = object();
+            return;
+        }
+
+        TangoScalarType* buffer = value_ptr->get_buffer();
+
+        // Convert to a list of lists
+        long offset = 0;
+        for(int it=1; it>=0; --it) { // 2 iterations: read part/write part
+            boost::python::list result;
+            if (isImage) {
+                const int dim_x = it? self.get_dim_x() : self.get_written_dim_x();
+                const int dim_y = it? self.get_dim_y() : self.get_written_dim_y();
+
+                for (int y=0; y < dim_y; ++y) {
+                    boost::python::list row;
+                    for (int x=0; x < dim_x; ++x)
+                        row.append(python_tangocpp<tangoTypeConst>::to_python(buffer[offset + x + y*dim_x]));
+                    result.append(row);
+                }
+                offset += dim_x*dim_y;
+            } else {
+                const int dim_x = it? self.get_dim_x() : self.get_written_dim_x();
+                for (int x=0; x < dim_x; ++x)
+                    result.append(python_tangocpp<tangoTypeConst>::to_python(buffer[x]));
+                offset += dim_x;
+            }
+            py_value.attr(it? value_attr_name : w_value_attr_name) = result;
+        }
+    }
+
+    template<long tangoTypeConst>
+    static inline void _update_array_values_as_pytango3(Tango::DeviceAttribute &self, bool isImage, object py_value)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+        typedef typename TANGO_const2arraytype(tangoTypeConst) TangoArrayType;
+
+        // Extract the actual data from Tango::DeviceAttribute (self)
+        TangoArrayType* value_ptr = 0;
+        try {
+            self >> value_ptr;
+        } catch (Tango::DevFailed &e ) {
+            if (strcmp(e.errors[0].reason.in(),"API_EmptyDeviceAttribute") != 0)
+                throw;
+        }
+        std::auto_ptr<TangoArrayType> guard_value_ptr(value_ptr);
+
+        if (value_ptr == 0) {
+            // Empty device attribute
+            py_value.attr(value_attr_name) = boost::python::list();
+            py_value.attr(w_value_attr_name) = object();
+            return;
+        }
+
+        TangoScalarType* buffer = value_ptr->get_buffer();
+
+        long sz = value_ptr->length();
+        boost::python::list res;
+        for (long x =0; x<sz; ++x) {
+            res.append(python_tangocpp<tangoTypeConst>::to_python(buffer[x]));
+        }
+
+        py_value.attr(value_attr_name) = res;
+        py_value.attr(w_value_attr_name) = object();
+    }
+
+    template<>
+    inline void _update_array_values_as_pytango3<Tango::DEV_ENCODED>(Tango::DeviceAttribute &self, bool isImage, object py_value)
+    {
+        /// @todo DevEncoded didn't even exist in PyTango3...
+        _update_array_values_as_tuples<Tango::DEV_ENCODED>(self, isImage, py_value);
+    }
+
+    template<long tangoTypeConst>
+    void _update_array_values_as_tuples(Tango::DeviceAttribute &self, bool isImage, object py_value)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+        typedef typename TANGO_const2arraytype(tangoTypeConst) TangoArrayType;
+
+        // Extract the actual data from Tango::DeviceAttribute (self)
+        TangoArrayType* value_ptr = 0;
+        try {
+            self >> value_ptr;
+        } catch (Tango::DevFailed &e ) {
+            if (strcmp(e.errors[0].reason.in(),"API_EmptyDeviceAttribute") != 0)
+                throw;
+        }
+        std::auto_ptr<TangoArrayType> guard_value_ptr(value_ptr);
+
+        if (value_ptr == 0) {
+            // Empty device attribute
+            py_value.attr(value_attr_name) = boost::python::tuple();
+            py_value.attr(w_value_attr_name) = object();
+            return;
+        }
+
+        TangoScalarType* buffer = value_ptr->get_buffer();
+
+        // Convert to a list of lists
+        long offset = 0;
+        for(int it=1; it>=0; --it) { // 2 iterations: read part/write part
+            //boost::python::list result;
+            object result_guard;
+            if (isImage) {
+                const int dim_x = it? self.get_dim_x() : self.get_written_dim_x();
+                const int dim_y = it? self.get_dim_y() : self.get_written_dim_y();
+
+                PyObject * result = PyTuple_New(dim_y);
+                if (!result)
+                    boost::python::throw_error_already_set();
+                result_guard = object(handle<>(result));
+
+                for (int y=0; y < dim_y; ++y) {
+                    //boost::python::list row;
+                    PyObject * row = PyTuple_New(dim_x);
+                    if (!row)
+                        boost::python::throw_error_already_set();
+                    object row_guard = object(handle<>(row));
+                    for (int x=0; x < dim_x; ++x) {
+                        object el = python_tangocpp<tangoTypeConst>::to_python(buffer[offset + x + y*dim_x]);
+                        PyTuple_SetItem(row, x, el.ptr());
+                        incref(el.ptr());
+                    }
+                    PyTuple_SetItem(result, y, row);
+                    incref(row);
+                }
+                offset += dim_x*dim_y;
+            } else {
+                const int dim_x = it? self.get_dim_x() : self.get_written_dim_x();
+
+                PyObject * result = PyTuple_New(dim_x);
+                if (!result)
+                    boost::python::throw_error_already_set();
+                result_guard = object(handle<>(result));
+
+                for (int x=0; x < dim_x; ++x) {
+                    object el = python_tangocpp<tangoTypeConst>::to_python(buffer[x]);
+                    PyTuple_SetItem(result, x, el.ptr());
+                    incref(el.ptr());
+                }
+                offset += dim_x;
+            }
+            py_value.attr(it? value_attr_name : w_value_attr_name) = result_guard;
+        }
+    }
+
+    template<long tangoTypeConst>
+    static inline void _update_value_as_string(Tango::DeviceAttribute &self, object py_value)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+        typedef typename TANGO_const2arraytype(tangoTypeConst) TangoArrayType;
+
+        // Extract the actual data from Tango::DeviceAttribute (self)
+        TangoArrayType* value_ptr = 0;
+        try {
+            self >> value_ptr;
+        } catch (Tango::DevFailed &e ) {
+            if (strcmp(e.errors[0].reason.in(),"API_EmptyDeviceAttribute") != 0)
+                throw;
+        }
+        std::auto_ptr<TangoArrayType> guard_value_ptr(value_ptr);
+
+        if (value_ptr == 0) {
+            py_value.attr(value_attr_name) = boost::python::str();
+            py_value.attr(w_value_attr_name) = object();
+            return;
+        }
+
+        TangoScalarType* buffer = value_ptr->get_buffer();
+
+        const char *ch_ptr = reinterpret_cast<char *>(buffer);
+        size_t nb_bytes = value_ptr->length() * sizeof(TangoScalarType);
+
+        py_value.attr(value_attr_name) = str(ch_ptr, (size_t)nb_bytes);
+        py_value.attr(w_value_attr_name) = object();
+    }
+
+    void update_values(Tango::DeviceAttribute &self, object& py_value, PyTango::ExtractAs extract_as/*=ExtractAsNumpy*/)
+    {
+        // We do not want is_empty to launch an exception!!
+        self.reset_exceptions(Tango::DeviceAttribute::isempty_flag);
+        // self.get_type() already does self.is_empty()
+        const int data_type = self.get_type();
+        const bool is_empty = data_type < 0; /*self.is_empty()*/
+        const bool has_failed = self.has_failed();
+        Tango::AttrDataFormat data_format = self.get_data_format();
+
+        py_value.attr(is_empty_attr_name) = object(is_empty);
+        py_value.attr(has_failed_attr_name) = object(has_failed);
+        py_value.attr(type_attr_name) = object(static_cast<Tango::CmdArgType>(data_type));
+
+        if (has_failed || is_empty) {
+            // In none of this cases 'data_type' is valid so we cannot extract
+            py_value.attr(value_attr_name) = object();
+            py_value.attr(w_value_attr_name) = object();
+            return;
+        }
+
+        bool is_image = false;
+        switch (data_format) {
+            case Tango::SCALAR:
+                switch (extract_as)
+                {
+                    default:
+                    case PyTango::ExtractAsNumpy:
+                    case PyTango::ExtractAsTuple:
+                    case PyTango::ExtractAsList:
+                        TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(data_type, _update_scalar_values, self, py_value);
+                        break;
+                    case PyTango::ExtractAsString:
+                        TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(data_type, _update_value_as_string, self, py_value);
+                        break;
+                    case PyTango::ExtractAsPyTango3:
+                        TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(data_type, _update_scalar_values, self, py_value);
+                        py_value.attr("w_scalar_value") = py_value.attr(w_value_attr_name);
+                        break;
+                    case PyTango::ExtractAsNothing:
+                        break;
+                }
+                break;
+            case Tango::IMAGE:
+                is_image = true;
+            case Tango::SPECTRUM:
+                switch (extract_as)
+                {
+                    default:
+                    case PyTango::ExtractAsNumpy:
+#                   ifndef DISABLE_PYTANGO_NUMPY
+                        TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(data_type, _update_array_values,
+                                           self, is_image, py_value);
+                        break;
+#                   endif
+                    case PyTango::ExtractAsTuple:
+                        TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(data_type, _update_array_values_as_tuples,
+                                           self, is_image, py_value);
+                        break;
+                    case PyTango::ExtractAsList:
+                        TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(data_type, _update_array_values_as_lists,
+                                           self, is_image, py_value);
+                        break;
+                    case PyTango::ExtractAsString:
+                        TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(data_type, _update_value_as_string,
+                                           self, py_value);
+                        break;
+                    case PyTango::ExtractAsPyTango3:
+                        TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(data_type, _update_array_values_as_pytango3,
+                                           self, is_image, py_value);
+                        break;
+                    case PyTango::ExtractAsNothing:
+                        break;
+                }
+                break;
+            case Tango::FMT_UNKNOWN:
+            default:
+                raise_(PyExc_ValueError, "Can't extract data because: self.get_data_format()=FMT_UNKNOWN");
+                assert(false);
+        }
+    }
+
+    template<long tangoTypeConst>
+    static inline void _fill_scalar_attribute(Tango::DeviceAttribute & dev_attr, const object & py_value)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+
+    TangoScalarType value;
+    from_py<tangoTypeConst>::convert(py_value.ptr(), value);
+        dev_attr << const_cast<TangoScalarType&>(value);
+    }
+
+    template<>
+    inline void _fill_scalar_attribute<Tango::DEV_STRING>(Tango::DeviceAttribute & dev_attr, const object & py_value)
+    {
+        std::string value = extract<std::string>(py_value);
+        dev_attr << value;
+    }
+
+    template<>
+    inline void _fill_scalar_attribute<Tango::DEV_ENCODED>(Tango::DeviceAttribute & dev_attr, const object & py_value)
+    {
+        static const long tangoTypeConst = Tango::DEV_ENCODED;
+        typedef TANGO_const2type(tangoTypeConst) TangoScalarType;
+        typedef TANGO_const2arraytype(tangoTypeConst) TangoArrayType;
+
+        /// @todo test it!!
+
+        /// @todo Now I am accepting 2 strings: encoded_format, encoded_data. This
+        /// is far from a good solution, but its something...
+
+        if (boost::python::len(py_value) != 2) {
+            raise_(PyExc_TypeError, "Expecting a tuple of strings: encoded_format, encoded_data");
+        }
+
+        boost::python::object encoded_format_str = py_value[0];
+        boost::python::object encoded_data_str = py_value[1];
+
+        /// @todo not sure... second parameter of insert is a reference, does it
+        /// mean anything? Does he pretend to take ownership of the pointer or
+        /// is he making another copy? what should I do?
+        char* encoded_format = const_cast<char*>((extract<const char*>(encoded_format_str)()));
+        unsigned int encoded_data_len = boost::python::len(encoded_data_str);
+        unsigned char* encoded_data = reinterpret_cast<unsigned char*>(const_cast<char*>((extract<const char*>(encoded_data_str)())));
+        // void insert(char *&,unsigned char *&,unsigned int);
+        dev_attr.insert(encoded_format, encoded_data, encoded_data_len);
+
+        std::string value = extract<std::string>(py_value);
+        dev_attr << value;
+    }
+
+    template<long tangoTypeConst>
+    static inline void _fill_list_attribute(Tango::DeviceAttribute & dev_attr, const bool isImage, const object & py_value)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+        typedef typename TANGO_const2arraytype(tangoTypeConst) TangoArrayType;
+
+        long dim_x, dim_y, nelems;
+
+        // -- Check the dimensions
+        if (isImage) {
+            dim_y = len(py_value);
+            dim_x = len(py_value[0]);
+            nelems = dim_x * dim_y;
+        } else {
+            dim_x = len(py_value);
+            dim_y = 0;
+            nelems = dim_x;
+        }
+
+        // -- Allocate memory
+        std::auto_ptr<TangoArrayType> value;
+        TangoScalarType* buffer = TangoArrayType::allocbuf(nelems);
+        try {
+            value.reset(new TangoArrayType(nelems, nelems, buffer, true));
+        } catch(...) {
+            TangoArrayType::freebuf(buffer);
+            throw;
+        }
+
+        // -- Copy the sequence to the newly created buffer
+        if (isImage) {
+            for(long y = 0; y < dim_y; ++y) {
+                object py_sub = py_value[y];
+                if (len(py_sub) != dim_x)
+                    raise_(PyExc_TypeError, non_valid_image);
+                for(long x = 0; x < dim_x; ++x) {
+                    python_tangocpp<tangoTypeConst>::to_cpp(py_sub[x], buffer[x + y*dim_x]);
+                }
+            }
+        } else {
+            for(long x = 0; x < dim_x; ++x) {
+                python_tangocpp<tangoTypeConst>::to_cpp(py_value[x], buffer[x]);
+            }
+        }
+
+        // -- Insert it into the dev_attr
+        dev_attr.insert(value.get(), dim_x, dim_y);
+
+        // -- Final cleaning
+        value.release(); // Do not delete value, it is handled by dev_attr now!
+    }
+
+    template<>
+    inline void _fill_list_attribute<Tango::DEV_ENCODED>(Tango::DeviceAttribute & dev_attr, const bool isImage, const object & py_value)
+    {
+        /// @todo really? This is really not gonna happen?
+        // Unsupported
+        assert(false);
+    }
+
+    static inline object undefined_attribute(Tango::DeviceAttribute* self)
+    {
+        return object(); // None
+    }
+
+    void reset_values(Tango::DeviceAttribute & self, int data_type, Tango::AttrDataFormat data_format, object py_value)
+    {
+        bool isImage = false;
+        switch(data_format)
+        {
+            case Tango::SCALAR:
+                TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE( data_type, _fill_scalar_attribute, self, py_value );
+                break;
+            case Tango::IMAGE:
+                isImage = true;
+            case Tango::SPECTRUM:
+                // Why on earth? Why do we define _fill_numpy_attribute instead
+                // of just using _fill_list_attribute, if the latter accepts
+                // anything with operators "[]" and "len" defined?
+                // Well it seems that PyArray_GETITEM does something diferent
+                // and I get a value transformed into a python basic type,
+                // while py_value[y][x] gives me a numpy type (ej: numpy.bool_).
+                // Then the conversions between numpy types to c++ are not
+                // defined by boost while the conversions between python
+                // standard types and C++ are.
+#               ifdef DISABLE_PYTANGO_NUMPY
+                {
+                    TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE( data_type, _fill_list_attribute, self, isImage, py_value );
+                }
+#               else
+                {
+                    if (PyArray_Check(py_value.ptr()))
+                        TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE( data_type, _fill_numpy_attribute, self, isImage, py_value );
+                    else
+                        TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE( data_type, _fill_list_attribute, self, isImage, py_value );
+                    break;
+                }
+#               endif
+            default:
+                raise_(PyExc_TypeError, "unsupported data_format.");
+        }
+    }
+
+    void reset(Tango::DeviceAttribute & self, const Tango::AttributeInfo &attr_info, object py_value)
+    {
+        self.set_name(const_cast<std::string&>(attr_info.name));
+        reset_values(self, attr_info.data_type, attr_info.data_format, py_value);
+    }
+
+    void reset(Tango::DeviceAttribute & self, const std::string &attr_name, Tango::DeviceProxy &dev_proxy, object py_value)
+    {
+        Tango::AttributeInfoEx attr_info;
+        {
+            AutoPythonAllowThreads guard;
+            attr_info = dev_proxy.get_attribute_config(attr_name);
+        }
+        reset(self, attr_info, py_value);
+    }
+
+};
+
+void export_device_attribute()
+{
+    class_<Tango::DeviceAttribute> DeviceAttribute("DeviceAttribute",
+        init<>())
+    ;
+
+    scope da_scope = DeviceAttribute;
+
+    enum_<Tango::DeviceAttribute::except_flags>("except_flags")
+        .value("isempty_flag", Tango::DeviceAttribute::isempty_flag)
+        .value("wrongtype_flag", Tango::DeviceAttribute::wrongtype_flag)
+        .value("failed_flag", Tango::DeviceAttribute::failed_flag)
+        .value("numFlags", Tango::DeviceAttribute::numFlags)
+    ;
+
+    DeviceAttribute
+        .def(init<const Tango::DeviceAttribute &>())
+
+        .def_readwrite("name", &Tango::DeviceAttribute::name)
+
+        .def_readwrite("quality", &Tango::DeviceAttribute::quality)
+
+        .def_readwrite("time", &Tango::DeviceAttribute::time)
+
+        .add_property("dim_x", &Tango::DeviceAttribute::get_dim_x)
+
+        .add_property("dim_y", &Tango::DeviceAttribute::get_dim_y)
+
+        .add_property("w_dim_x", &Tango::DeviceAttribute::get_written_dim_x)
+
+        .add_property("w_dim_y", &Tango::DeviceAttribute::get_written_dim_y)
+
+        .add_property("r_dimension", &Tango::DeviceAttribute::get_r_dimension)
+
+        .add_property("w_dimension", &Tango::DeviceAttribute::get_w_dimension)
+
+        .add_property("nb_read", &Tango::DeviceAttribute::get_nb_read)
+
+        .add_property("nb_written", &Tango::DeviceAttribute::get_nb_written)
+
+        .add_property("data_format", &Tango::DeviceAttribute::get_data_format)
+            
+        .def("get_date", &Tango::DeviceAttribute::get_date,
+            return_internal_reference<>())
+
+        .def("get_err_stack", &Tango::DeviceAttribute::get_err_stack,
+            return_value_policy<copy_const_reference>())
+
+    ;
+}
diff --git a/src/device_attribute.h b/src/device_attribute.h
new file mode 100644
index 0000000..6b94c2b
--- /dev/null
+++ b/src/device_attribute.h
@@ -0,0 +1,159 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#pragma once
+
+#include <boost/python.hpp>
+#include <tango.h>
+#include <iostream>
+#include <string>
+
+#include "pyutils.h"
+#include "defs.h"
+
+namespace PyDeviceAttribute {
+
+/// @name Types
+/// @{
+    typedef std::auto_ptr<std::vector<Tango::DeviceAttribute> > AutoDevAttrVector;
+/// @}
+    
+    template<long tangoTypeConst>
+    void _update_array_values_as_tuples(Tango::DeviceAttribute &self, bool isImage, boost::python::object py_value);
+
+    /// Set the value of a DeviceAttribute from python (useful for write*)
+    void reset(Tango::DeviceAttribute& self, const Tango::AttributeInfo &attr_info, boost::python::object py_value);
+    void reset(Tango::DeviceAttribute & self, const std::string &attr_name, Tango::DeviceProxy &dev_proxy, boost::python::object py_value);
+
+    void update_values(Tango::DeviceAttribute &self, boost::python::object& py_value, PyTango::ExtractAs extract_as=PyTango::ExtractAsNumpy);
+
+    template<typename TDeviceAttribute>
+    void update_data_format(Tango::DeviceProxy & dev_proxy, TDeviceAttribute* first, size_t nelems)
+    {
+        // Older devices do not send arg_format. So we try to discover it from
+        // dim_x and dim_y. It is not perfect, sometimes we will get SCALAR for
+        // SPECTRUM with size 1 for example. In that case, we must ask tango
+        // for the actual value.
+        TDeviceAttribute* p = first;
+        std::vector<std::string> attr_names;
+        for (size_t n =0; n < nelems; ++n, ++p) {
+            if ( (p->data_format != Tango::FMT_UNKNOWN) || (p->has_failed()) )
+                continue;
+            if ( (p->get_dim_x() == 1) && (p->get_dim_y() == 0 ) ) {
+                attr_names.push_back(p->name);
+            } else if (p->get_dim_y() == 0) {
+                p->data_format = Tango::SPECTRUM;
+            } else {
+                p->data_format = Tango::IMAGE;
+            }
+        }
+        if (attr_names.size()) {
+            std::auto_ptr<Tango::AttributeInfoListEx> attr_infos;
+            {
+                AutoPythonAllowThreads guard;
+                p = first;
+                try
+                {
+                    attr_infos.reset(dev_proxy.get_attribute_config_ex(attr_names));
+                    for (size_t n=0, m=0; n < nelems; ++n, ++p) {
+                        if ((p->data_format == Tango::FMT_UNKNOWN) && (!p->has_failed())) {
+                            p->data_format = (*attr_infos)[m++].data_format;
+                        }
+                    }
+                }
+                catch(Tango::DevFailed &df)
+                {
+                    // if we fail to get info about the missing attributes from
+                    // the server (because it as shutdown, for example) we assume
+                    // that they are SCALAR since dim_x is 1
+                    for (size_t n=0; n < nelems; ++n, ++p) {
+                        if ((p->data_format == Tango::FMT_UNKNOWN) && (!p->has_failed())) {
+                            p->data_format = Tango::SCALAR;
+                        }
+                    }
+                }
+            }
+        }
+        return;
+    }
+
+    /// @param self The DeviceAttribute instance that the new python object
+    /// will represent. It must be allocated with new. The new python object
+    /// will handle it's destruction. There's never any reason to delete it
+    /// manually after a call to this: Even if this function fails, the
+    /// responsibility of destroying it will already be in py_value side or
+    /// the object will already be destroyed.
+    template<typename TDeviceAttribute>
+    boost::python::object convert_to_python(TDeviceAttribute* self, PyTango::ExtractAs extract_as)
+    {
+        using namespace boost::python;
+        object py_value;
+        try {
+            py_value = object(
+                    handle<>(
+                        to_python_indirect<
+                            TDeviceAttribute*,
+                            detail::make_owning_holder>()(self)));
+        } catch (...) {
+            delete self;
+            throw;
+        }
+
+        update_values(*self, py_value, extract_as);
+        return py_value;
+    }
+
+    /// See the other convert_to_python version. Here we get a vector of
+    /// DeviceAttributes. The responsibility to deallocate it is always from
+    /// the caller (we will make a copy). This responsibility is unavoidable
+    /// as we get a reference to auto_ptr -> the caller must use an auto_ptr,
+    /// so the memory will finally be deleted.
+    template<typename TDeviceAttribute>
+    boost::python::object convert_to_python(const std::auto_ptr<std::vector<TDeviceAttribute> >& dev_attr_vec, Tango::DeviceProxy & dev_proxy, PyTango::ExtractAs extract_as)
+    {
+        update_data_format(dev_proxy, &(*dev_attr_vec)[0], dev_attr_vec->size());
+
+        // Convert the c++ vector of DeviceAttribute into a pythonic list
+        boost::python::list ls;
+        typename std::vector<TDeviceAttribute>::const_iterator i, e = dev_attr_vec->end();
+        for (i = dev_attr_vec->begin(); i != e; ++i)
+            ls.append( convert_to_python(new TDeviceAttribute(*i), extract_as) );
+        return ls;
+    }
+
+    /// Convert a DeviceAttribute to python (useful for read*)
+    /// @param dev_attr Should be a pointer allocated with new. You can forget
+    ///                 about deallocating this object (python will do it) even
+    ///                 if the call to convert_to_python fails.
+    /// @param dev_proxy Device proxy where the value was got. DeviceAttribute
+    ///                 sent by older tango versions do not have all the
+    ///                 necessary information to extract the values, so we
+    ///                 may need to ask.
+    /// @param extract_as See ExtractAs enum.
+    template<typename TDeviceAttribute>
+    boost::python::object convert_to_python(TDeviceAttribute* dev_attr, Tango::DeviceProxy & dev_proxy, PyTango::ExtractAs extract_as)
+    {
+        update_data_format(dev_proxy, dev_attr, 1);
+        return convert_to_python(dev_attr, extract_as);
+    }
+}
diff --git a/src/device_attribute_config.cpp b/src/device_attribute_config.cpp
new file mode 100644
index 0000000..dd07798
--- /dev/null
+++ b/src/device_attribute_config.cpp
@@ -0,0 +1,51 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_device_attribute_config()
+{
+    class_<Tango::DeviceAttributeConfig>("DeviceAttributeConfig")
+        .def_readonly("name", &Tango::DeviceAttributeConfig::name)
+        .def_readonly("writable", &Tango::DeviceAttributeConfig::writable)
+        .def_readonly("data_format", &Tango::DeviceAttributeConfig::data_format)
+        .def_readonly("data_type", &Tango::DeviceAttributeConfig::data_type)
+        .def_readonly("max_dim_x", &Tango::DeviceAttributeConfig::max_dim_x)
+        .def_readonly("max_dim_y", &Tango::DeviceAttributeConfig::max_dim_y)
+        .def_readwrite("description", &Tango::DeviceAttributeConfig::description)
+        .def_readwrite("label", &Tango::DeviceAttributeConfig::label)
+        .def_readwrite("unit", &Tango::DeviceAttributeConfig::unit)
+        .def_readwrite("standard_unit", &Tango::DeviceAttributeConfig::standard_unit)
+        .def_readwrite("display_unit", &Tango::DeviceAttributeConfig::display_unit)
+        .def_readwrite("format", &Tango::DeviceAttributeConfig::format)
+        .def_readwrite("min_value", &Tango::DeviceAttributeConfig::min_value)
+        .def_readwrite("max_value", &Tango::DeviceAttributeConfig::max_value)
+        .def_readwrite("min_alarm", &Tango::DeviceAttributeConfig::min_alarm)
+        .def_readwrite("max_alarm", &Tango::DeviceAttributeConfig::max_alarm)
+        .def_readwrite("writable_attr_name", &Tango::DeviceAttributeConfig::writable_attr_name)
+        .def_readwrite("extensions", &Tango::DeviceAttributeConfig::extensions)
+    ;
+}
diff --git a/src/device_attribute_history.cpp b/src/device_attribute_history.cpp
new file mode 100644
index 0000000..4089909
--- /dev/null
+++ b/src/device_attribute_history.cpp
@@ -0,0 +1,40 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_device_attribute_history()
+{
+
+    class_<Tango::DeviceAttributeHistory, bases<Tango::DeviceAttribute> >
+            DeviceAttributeHistory("DeviceAttributeHistory", init<>());
+
+    DeviceAttributeHistory
+        .def(init<const Tango::DeviceAttributeHistory &>())
+
+        .def("has_failed", &Tango::DeviceAttributeHistory::has_failed)
+    ;
+}
diff --git a/src/device_attribute_numpy.hpp b/src/device_attribute_numpy.hpp
new file mode 100644
index 0000000..2f2aba3
--- /dev/null
+++ b/src/device_attribute_numpy.hpp
@@ -0,0 +1,265 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+
+// This header file is just some template functions moved apart from
+// device_attribute.cpp, and should only be included there.
+
+#pragma once
+
+namespace PyDeviceAttribute {
+
+    /// This callback is run to delete Tango::DevVarXArray* objects.
+    /// It is called by python. The array was associated with an attribute
+    /// value object that is not being used anymore.
+    /// @param ptr_ The array object.
+    /// @param type_ The type of the array objects. We need it to convert ptr_
+    ///              to the proper type before deleting it. ex: Tango::DEV_SHORT.
+    static void _dev_var_x_array_deleter(void * ptr_, void *type_)
+    {
+        long type = reinterpret_cast<long>(type_);
+
+        TANGO_DO_ON_ATTRIBUTE_DATA_TYPE(type,
+            delete static_cast<TANGO_const2arraytype(tangoTypeConst)*>(ptr_);
+        );
+    }
+
+    template<long tangoTypeConst>
+    static inline void _update_array_values(Tango::DeviceAttribute &self, bool isImage, object py_value)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+        typedef typename TANGO_const2arraytype(tangoTypeConst) TangoArrayType;
+
+        // Extract the actual data from Tango::DeviceAttribute (self)
+        TangoArrayType* value_ptr = 0;
+        try {
+            self >> value_ptr;
+        } catch (Tango::DevFailed &e ) {
+            if (strcmp(e.errors[0].reason.in(),"API_EmptyDeviceAttribute") != 0)
+                throw;
+        }
+
+        static const int typenum = TANGO_const2numpy(tangoTypeConst);
+
+        if (value_ptr == 0) {
+            // Empty device attribute
+            PyObject* value = PyArray_SimpleNew(0, 0, typenum);
+            if (!value)
+                throw_error_already_set();
+            py_value.attr(value_attr_name) = object(handle<>(value));
+            py_value.attr(w_value_attr_name) = object();
+            return;
+        }
+
+        TangoScalarType* buffer = value_ptr->get_buffer();
+
+        npy_intp dims[2];
+        int nd = 1;
+        size_t write_part_offset = 0;
+        if (isImage) {
+            nd = 2;
+            dims[1] = self.get_dim_x();
+            dims[0] = self.get_dim_y();
+            write_part_offset = dims[1] * dims[0];
+        } else {
+            nd = 1;
+            dims[0] = self.get_dim_x();
+            write_part_offset = dims[0];
+        }
+
+        // Create a new numpy.ndarray() object. It uses ch_ptr as the data,
+        // so no costy memory copies when handling big images.
+        char *ch_ptr = reinterpret_cast<char *>(buffer);
+
+        PyObject* array = PyArray_SimpleNewFromData(nd, dims, typenum, ch_ptr);
+        if (!array) {
+            delete value_ptr;
+            throw_error_already_set();
+        }
+
+        // Create the numpy array for the write part. It will be stored in
+        // another place.
+        PyObject* warray = 0;
+        if (self.get_written_dim_x() != 0) {
+            if (isImage) {
+                nd = 2;
+                dims[1] = self.get_written_dim_x();
+                dims[0] = self.get_written_dim_y();
+            } else {
+                nd = 1;
+                dims[0] = self.get_written_dim_x();
+            }
+            char* w_ch_ptr = reinterpret_cast<char *>( buffer + write_part_offset );
+            warray = PyArray_SimpleNewFromData(nd, dims, typenum, w_ch_ptr);
+            if (!warray) {
+                Py_XDECREF(array);
+                delete value_ptr;
+                throw_error_already_set();
+            }
+        }
+
+        // numpy.ndarray() does not own it's memory, so we need to manage it.
+        // We can assign a 'base' object that will be informed (decref'd) when
+        // the last copy of numpy.ndarray() disappears.
+        // PyCObject is intended for that kind of things. It's seen as a
+        // black box object from python. We assign him a function to be called
+        // when it is deleted -> the function deletes de data.
+        PyObject* guard = PyCObject_FromVoidPtrAndDesc(
+                static_cast<void*>(value_ptr),
+                reinterpret_cast<void*>(tangoTypeConst),
+                _dev_var_x_array_deleter);
+        if (!guard ) {
+            Py_XDECREF(array);
+            Py_XDECREF(warray);
+            delete value_ptr;
+            throw_error_already_set();
+        }
+
+        PyArray_BASE(array) = guard;
+        py_value.attr(value_attr_name) = boost::python::object(boost::python::handle<>(array));
+
+        // The original C api object storing the data is the same for the
+        // read data and the write data. so, both array and warray share
+        // the same 'base' (guard). Thus, the data will not be deleted until
+        // neither is accessed anymore.
+        if (warray) {
+            Py_INCREF(guard);
+            PyArray_BASE(warray) = guard;
+            py_value.attr(w_value_attr_name) = boost::python::object(boost::python::handle<>(warray));
+        } else
+            py_value.attr(w_value_attr_name) = object();
+        // py_value.attr("__internal_data") = object(handle<>(borrowed(guard)));
+    }
+
+    template<>
+    inline void _update_array_values<Tango::DEV_STRING>(Tango::DeviceAttribute &self, bool isImage, object py_value)
+    {
+        _update_array_values_as_tuples<Tango::DEV_STRING>(self, isImage, py_value);
+    }
+
+    template<>
+    inline void _update_array_values<Tango::DEV_ENCODED>(Tango::DeviceAttribute &self, bool isImage, object py_value)
+    {
+        /// @todo Sure, it is not necessary?
+        assert(false);
+    }
+
+    // template<long tangoTypeConst>
+    // static inline void _update_array_values(PythonDeviceAttribute &self, bool isImage)
+    // {
+    //     return _update_array_values_numpy<tangoTypeConst>(self, isImage);
+    // }
+
+    template<long tangoTypeConst>
+    static inline void _fill_numpy_attribute(Tango::DeviceAttribute & dev_attr, const bool isImage, const object & py_value)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+        typedef typename TANGO_const2arraytype(tangoTypeConst) TangoArrayType;
+
+        // -- Check dimensions
+        unsigned long dim_x=0, dim_y=0, nelems=0;
+        bool ok;
+        switch (PyArray_NDIM(py_value.ptr())) {
+            case 2: // -- Image
+                ok = isImage;
+                dim_x = PyArray_DIM(py_value.ptr(), 1);
+                dim_y = PyArray_DIM(py_value.ptr(), 0);
+                nelems = dim_x*dim_y;
+                break;
+            case 1: // -- Spectrum
+                ok = !isImage;
+                dim_x = PyArray_DIM(py_value.ptr(), 0);
+                dim_y = 0;
+                nelems = dim_x;
+                break;
+            default: // -- WTF?!!?
+                ok = false;
+                break;
+        }
+        if (!ok)
+            raise_(PyExc_TypeError, isImage? non_valid_image : non_valid_spectrum);
+
+        // -- Allocate memory for the new data object
+        std::auto_ptr<TangoArrayType> value;
+        TangoScalarType* buffer = TangoArrayType::allocbuf(nelems);
+        try {
+            value.reset(new TangoArrayType(nelems, nelems, buffer, true));
+        } catch(...) {
+            TangoArrayType::freebuf(buffer);
+            throw;
+        }
+
+        // -- Copy from numpy.array to TangoArrayType...
+        PyArrayIterObject *iter;
+        PyObject *array = py_value.ptr();
+        iter = (PyArrayIterObject *)PyArray_IterNew(array);
+        if (!iter)
+            throw_error_already_set();
+        object iter_guard(handle<>(iter));
+
+        if (isImage) {
+            // Why not use PyArray_ITER_NEXT() instead of PyArray_ITER_GOTO()?
+            // We could do a single while(iter->index < iter->size) instead
+            // of the double "for".
+            // I did this and it worked in the sense that it went across
+            // the correct number of elements but... I did not know the
+            // x and y position it corresponded! Yes, 'iter' has a coordinates
+            // field, but it was always [0,0], never updated!!
+            unsigned long coordinates[2];
+            unsigned long &x = coordinates[1];
+            unsigned long &y = coordinates[0];
+            for (y=0; y < dim_y; ++y) {
+                for (x=0; x < dim_x; ++x) {
+                    PyArray_ITER_GOTO(iter, coordinates);
+
+                    PyObject* dataObj = PyArray_GETITEM(array, iter->dataptr);
+                    const object py_data = object( handle<>( dataObj ) );
+
+                    buffer[y*dim_x + x] = extract<TangoScalarType>(py_data);
+                }
+            }
+        } else {
+            for (unsigned long x=0; x < dim_x; ++x) {
+                PyObject* dataObj = PyArray_GETITEM(array, iter->dataptr);
+                const object py_data = object( handle<>( dataObj ) );
+
+                buffer[x] = extract<TangoScalarType>(py_data);
+
+                PyArray_ITER_NEXT(iter);
+            }
+        }
+
+        // -- Insert into device attribute
+        dev_attr.insert( value.get(), dim_x, dim_y );
+
+        // -- Final cleaning...
+        value.release(); // Do not delete value, it is handled by dev_attr now!
+    }
+
+    template<>
+    inline void _fill_numpy_attribute<Tango::DEV_ENCODED>(Tango::DeviceAttribute & dev_attr, const bool isImage, const object & py_value)
+    {
+        // Unsupported
+        assert(false);
+    }
+}
diff --git a/src/device_data.cpp b/src/device_data.cpp
new file mode 100644
index 0000000..8757a8d
--- /dev/null
+++ b/src/device_data.cpp
@@ -0,0 +1,211 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <boost/mpl/if.hpp>
+#include <tango.h>
+#include <iostream>
+#include <string>
+
+#include "pytgutils.h"
+#include "fast_from_py.h"
+
+using namespace boost::python;
+
+#ifndef DISABLE_PYTANGO_NUMPY
+#   include "to_py_numpy.hpp"
+#endif
+
+namespace PyDeviceData {
+
+    Tango::CmdArgType get_type(Tango::DeviceData &self)
+    {
+        /// @todo This should change in Tango itself, get_type should not return int!!
+        return static_cast<Tango::CmdArgType>(self.get_type());
+    }
+    
+    /// @name Scalar Insertion
+    /// @{
+        template <long tangoTypeConst>
+        void insert_scalar(Tango::DeviceData &self, object py_value)
+        {
+            typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+            TangoScalarType val;
+            val = boost::python::extract<TangoScalarType>(py_value);
+            self << val;
+        }
+        template <>
+        void insert_scalar<Tango::DEV_VOID>(Tango::DeviceData &self, object py_value)
+        {
+            raise_(PyExc_TypeError, "Trying to insert a value in a DEV_VOID DeviceData!");
+        }
+    /// @}
+    // ~Scalar Insertion
+    // -----------------------------------------------------------------------
+
+    /// @name Array Insertion
+    /// @{
+        template <long tangoArrayTypeConst>
+        void insert_array(Tango::DeviceData &self, object py_value)
+        {            
+            typedef typename TANGO_const2type(tangoArrayTypeConst) TangoArrayType;
+
+            // self << val; -->> This ends up doing:
+            // inline void operator << (DevVarUShortArray* datum) 
+            // { any.inout() <<= datum;}
+            // So:
+            //  - We loose ownership of the pointer, should not remove it
+            //  - it's a CORBA object who gets ownership, not a buggy Tango
+            //    thing. So the last parameter to fast_convert2array is false
+            TangoArrayType* val = fast_convert2array<tangoArrayTypeConst>(py_value);
+            self << val;
+        }
+    /// @}
+    // ~Array Insertion
+    // -----------------------------------------------------------------------
+
+    /// @name Scalar Extraction
+    /// @{
+        template <long tangoTypeConst>
+        object extract_scalar(Tango::DeviceData &self)
+        {
+            typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+            /// @todo CONST_DEV_STRING ell el tracta com DEV_STRING
+            TangoScalarType val;
+            self >> val;
+            return boost::python::object(val);
+        }
+
+        template <>
+        object extract_scalar<Tango::DEV_VOID>(Tango::DeviceData &self)
+        {
+            return boost::python::object();
+        }
+
+        template <>
+        object extract_scalar<Tango::DEV_STRING>(Tango::DeviceData &self)
+        {
+            typedef std::string TangoScalarType;
+            TangoScalarType val;
+            self >> val;
+            return boost::python::object(val);
+        }
+    /// @}
+    // ~Scalar Extraction
+    // -----------------------------------------------------------------------
+
+    /// @name Array extraction
+    /// @{       
+
+        template <long tangoArrayTypeConst>
+        object extract_array(Tango::DeviceData &self, object &py_self, PyTango::ExtractAs extract_as)
+        {
+            typedef typename TANGO_const2type(tangoArrayTypeConst) TangoArrayType;
+            
+            // const is the pointed, not the pointer. So cannot modify the data.
+            // And that's because the data is still inside "self" after extracting.
+            // This also means that we are not supposed to "delete" tmp_ptr.
+            const TangoArrayType* tmp_ptr;
+            self >> tmp_ptr;
+
+            switch (extract_as)
+            {
+                default:
+                case PyTango::ExtractAsNumpy:
+#                 ifndef DISABLE_PYTANGO_NUMPY
+                    return to_py_numpy<tangoArrayTypeConst>(tmp_ptr, py_self);
+#                 endif
+                case PyTango::ExtractAsList:
+                case PyTango::ExtractAsPyTango3:
+                    return to_py_list(tmp_ptr);
+                case PyTango::ExtractAsTuple:
+                    return to_py_tuple(tmp_ptr);
+                case PyTango::ExtractAsString: /// @todo
+                case PyTango::ExtractAsNothing:
+                    return object();
+            }
+        }
+    /// @}
+    // ~Array Extraction
+    // -----------------------------------------------------------------------
+
+    object extract(object py_self, PyTango::ExtractAs extract_as)
+    {
+        Tango::DeviceData &self = boost::python::extract<Tango::DeviceData &>(py_self);
+        
+        TANGO_DO_ON_DEVICE_DATA_TYPE(self.get_type(),
+            return extract_scalar<tangoTypeConst>(self);
+        ,
+            return extract_array<tangoTypeConst>(self, py_self, extract_as);
+        );
+        return object();
+    }
+
+    void insert(Tango::DeviceData &self, long data_type, object py_value)
+    {
+        TANGO_DO_ON_DEVICE_DATA_TYPE(data_type,
+            insert_scalar<tangoTypeConst>(self, py_value);
+        , 
+            insert_array<tangoTypeConst>(self, py_value);
+        );
+    }
+}
+
+void export_device_data()
+{
+    class_<Tango::DeviceData> DeviceData("DeviceData",
+        init<>())
+    ;
+
+    scope scope_dd = DeviceData;
+
+    /// @todo get rid of except_flags everywhere... or really use and export them everywhere!
+    enum_<Tango::DeviceData::except_flags>("except_flags")
+        .value("isempty_flag", Tango::DeviceData::isempty_flag)
+        .value("wrongtype_flag", Tango::DeviceData::wrongtype_flag)
+        .value("numFlags", Tango::DeviceData::numFlags)
+    ;
+
+    DeviceData
+        .def(init<const Tango::DeviceData &>())
+
+        .def("extract",
+            &PyDeviceData::extract,
+            ( arg_("self"), arg_("extract_as")=PyTango::ExtractAsNumpy ))
+
+        .def("insert", &PyDeviceData::insert,
+            (arg_("self"), arg_("data_type"), arg_("value")))
+
+        /// @todo do not throw exceptions!!
+        .def("is_empty", &Tango::DeviceData::is_empty)
+
+// TODO
+//	void exceptions(bitset<numFlags> fl) {exceptions_flags = fl;}
+//	bitset<numFlags> exceptions() {return exceptions_flags;}
+//	void reset_exceptions(except_flags fl) {exceptions_flags.reset((size_t)fl);}
+//	void set_exceptions(except_flags fl) {exceptions_flags.set((size_t)fl);}
+
+        .def("get_type", &PyDeviceData::get_type)
+    ;
+
+}
diff --git a/src/device_data_history.cpp b/src/device_data_history.cpp
new file mode 100644
index 0000000..ffcbe30
--- /dev/null
+++ b/src/device_data_history.cpp
@@ -0,0 +1,43 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_device_data_history()
+{
+    class_<Tango::DeviceDataHistory, bases<Tango::DeviceData> >
+            DeviceDataHistory("DeviceDataHistory", init<>());
+
+    DeviceDataHistory
+        .def(init<const Tango::DeviceDataHistory &>())
+
+        .def("has_failed", &Tango::DeviceDataHistory::has_failed)
+        .def("get_date", &Tango::DeviceDataHistory::get_date,
+            return_internal_reference<>())
+        .def("get_err_stack", &Tango::DeviceDataHistory::get_err_stack,
+            return_value_policy<copy_const_reference>())
+    ;
+}
diff --git a/src/device_info.cpp b/src/device_info.cpp
new file mode 100644
index 0000000..ee16d18
--- /dev/null
+++ b/src/device_info.cpp
@@ -0,0 +1,46 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_device_info()
+{
+    class_<Tango::DeviceInfo>("DeviceInfo",
+        "A structure containing available information for a device with the\n"
+        "following members,\n"
+        " - dev_class : string\n"
+        " - server_id : string\n"
+        " - server_host : string\n"
+        " - server_version : integer\n"
+        " - doc_url : string")
+        .def_readonly("dev_class", &Tango::DeviceInfo::dev_class)
+        .def_readonly("server_id", &Tango::DeviceInfo::server_id)
+        .def_readonly("server_host", &Tango::DeviceInfo::server_host)
+        .def_readonly("server_version", &Tango::DeviceInfo::server_version)
+        .def_readonly("doc_url", &Tango::DeviceInfo::doc_url)
+        .def_readonly("dev_type", &Tango::DeviceInfo::dev_type)
+    ;
+}
diff --git a/src/device_proxy.cpp b/src/device_proxy.cpp
new file mode 100644
index 0000000..654e887
--- /dev/null
+++ b/src/device_proxy.cpp
@@ -0,0 +1,753 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <boost/python/return_value_policy.hpp>
+#include <tango.h>
+#include <string>
+#include <memory>
+
+#include "device_attribute.h"
+#include "callback.h"
+
+#include "defs.h"
+#include "pytgutils.h"
+
+using namespace boost::python;
+
+extern const char *param_must_be_seq;
+extern const char *unreachable_code;
+extern const char *non_string_seq;
+
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(lock_overloads, Tango::DeviceProxy::lock, 0, 1);
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(unlock_overloads, Tango::DeviceProxy::unlock, 0, 1);
+
+namespace PyDeviceProxy
+{
+    struct PickleSuite : pickle_suite
+    {
+        static tuple getinitargs(Tango::DeviceProxy& self)
+        {
+            std::string ret = self.get_db_host() + ":" + self.get_db_port() + "/" + self.dev_name();
+            return make_tuple(ret);
+        }
+    };
+    
+    static inline Tango::DevState state(Tango::DeviceProxy& self)
+    {
+        AutoPythonAllowThreads guard;
+        return self.state();
+    }
+
+    static inline std::string status(Tango::DeviceProxy& self)
+    {
+        AutoPythonAllowThreads guard;
+        return self.status();
+    }
+
+    static inline int ping(Tango::DeviceProxy& self)
+    {
+        AutoPythonAllowThreads guard;
+        return self.ping();
+    }
+
+    static inline void pylist_to_devattrs(Tango::DeviceProxy& self, object &py_list, std::vector<Tango::DeviceAttribute> &dev_attrs)
+    {
+        std::vector<std::string> attr_names;
+        std::vector<object> py_values;
+        long size = len(py_list);
+
+        // Fill attr_names and py_values
+        for (long n = 0; n < size; ++n) {
+            object tup = py_list[n];
+            std::string attr_name = extract<std::string>(tup[0]);
+            attr_names.push_back(attr_name);
+            py_values.push_back(tup[1]);
+        }
+
+        // Get attr_info for all the attr_names
+        std::auto_ptr<Tango::AttributeInfoListEx> attr_infos;
+        {
+            AutoPythonAllowThreads guard;
+            attr_infos.reset(self.get_attribute_config_ex(attr_names));
+        }
+
+        // Now prepare dev_attrs with attr_infos and py_values
+        dev_attrs.resize(size);
+        for (long n = 0; n < size; ++n) {
+            PyDeviceAttribute::reset(dev_attrs[n], (*attr_infos)[n], py_values[n]);
+        }
+    }
+
+    static inline object read_attribute(Tango::DeviceProxy& self, const string & attr_name, PyTango::ExtractAs extract_as)
+    {
+        // Even if there's an exception in convert_to_python, the
+        // DeviceAttribute will be deleted there, so we don't need to worry.
+        Tango::DeviceAttribute* dev_attr = 0;
+        {
+            AutoPythonAllowThreads guard;
+            dev_attr = \
+                    new Tango::DeviceAttribute(self.read_attribute(attr_name.c_str()));
+        }
+        return PyDeviceAttribute::convert_to_python(dev_attr, self, extract_as);
+    }
+
+    static inline object read_attributes(Tango::DeviceProxy& self, object py_attr_names, PyTango::ExtractAs extract_as)
+    {
+        CSequenceFromPython<StdStringVector> attr_names(py_attr_names);
+
+        PyDeviceAttribute::AutoDevAttrVector dev_attr_vec;
+        {
+            AutoPythonAllowThreads guard;
+            dev_attr_vec.reset(self.read_attributes(*attr_names));
+        }
+
+        return PyDeviceAttribute::convert_to_python(dev_attr_vec, self, extract_as);
+    }
+
+    static inline void write_attribute(Tango::DeviceProxy& self, const Tango::AttributeInfo & attr_info, object py_value)
+    {
+
+        Tango::DeviceAttribute da;
+        PyDeviceAttribute::reset(da, attr_info, py_value);
+        AutoPythonAllowThreads guard;
+        self.write_attribute(da);
+    }
+
+    static inline void write_attribute(Tango::DeviceProxy& self, const string & attr_name, object py_value)
+    {
+        Tango::DeviceAttribute dev_attr;
+        PyDeviceAttribute::reset(dev_attr, attr_name, self, py_value);
+        {
+            AutoPythonAllowThreads guard;
+            self.write_attribute(dev_attr);
+        }
+    }
+
+    static inline void write_attributes(Tango::DeviceProxy& self, object py_list)
+    {
+        std::vector<Tango::DeviceAttribute> dev_attrs;
+        pylist_to_devattrs(self, py_list, dev_attrs);
+
+        AutoPythonAllowThreads guard;
+        self.write_attributes(dev_attrs);
+    }
+
+    static inline object write_read_attribute(Tango::DeviceProxy& self, const string & attr_name, object py_value, PyTango::ExtractAs extract_as)
+    {
+        Tango::DeviceAttribute w_dev_attr;
+        std::auto_ptr<Tango::DeviceAttribute> r_dev_attr(0);
+
+        // Prepare dev_attr structure
+        PyDeviceAttribute::reset(w_dev_attr, attr_name, self, py_value);
+
+        // Do the actual write_read_attribute thing...
+        {
+            AutoPythonAllowThreads guard;
+            r_dev_attr.reset(new Tango::DeviceAttribute(self.write_read_attribute(w_dev_attr)));
+        }
+
+        // Convert the result back to python
+        return PyDeviceAttribute::convert_to_python(r_dev_attr.release(), self, extract_as);
+    }
+
+
+    static inline vector<Tango::DeviceDataHistory>*
+            command_history(Tango::DeviceProxy& self, const std::string & cmd_name, int depth)
+    {
+        AutoPythonAllowThreads guard;
+        return self.command_history(const_cast<std::string&>(cmd_name), depth);
+    }
+
+    static inline object
+            attribute_history(Tango::DeviceProxy& self, const std::string & attr_name, int depth, PyTango::ExtractAs extract_as)
+    {
+        std::auto_ptr< vector<Tango::DeviceAttributeHistory> > att_hist;
+        {
+            AutoPythonAllowThreads guard;
+            att_hist.reset(self.attribute_history(const_cast<std::string&>(attr_name), depth));
+        }
+        return PyDeviceAttribute::convert_to_python(att_hist, self, extract_as);
+    }
+
+
+    static inline long read_attributes_asynch(Tango::DeviceProxy& self, object py_attr_names)
+    {
+        CSequenceFromPython<StdStringVector> attr_names(py_attr_names);
+
+        AutoPythonAllowThreads guard;
+        return self.read_attributes_asynch(*attr_names);
+    }
+
+
+
+    static inline object read_attributes_reply(Tango::DeviceProxy& self, long id, PyTango::ExtractAs extract_as)
+    {
+        PyDeviceAttribute::AutoDevAttrVector dev_attr_vec;
+        {
+            AutoPythonAllowThreads guard;
+            dev_attr_vec.reset(self.read_attributes_reply(id));
+        }
+        return PyDeviceAttribute::convert_to_python(dev_attr_vec, self, extract_as);
+    }
+
+    static inline object read_attributes_reply(Tango::DeviceProxy& self, long id, long timeout, PyTango::ExtractAs extract_as)
+    {
+        PyDeviceAttribute::AutoDevAttrVector dev_attr_vec;
+        {
+            AutoPythonAllowThreads guard;
+            dev_attr_vec.reset(self.read_attributes_reply(id, timeout));
+        }
+        return PyDeviceAttribute::convert_to_python(dev_attr_vec, self, extract_as);
+    }
+
+    static inline long write_attributes_asynch(Tango::DeviceProxy& self, object py_list)
+    {
+        std::vector<Tango::DeviceAttribute> dev_attrs;
+        pylist_to_devattrs(self, py_list, dev_attrs);
+
+        AutoPythonAllowThreads guard;
+        return self.write_attributes_asynch(dev_attrs);
+    }
+
+    static inline void write_attributes_reply(Tango::DeviceProxy& self, long id, long timestamp)
+    {
+        AutoPythonAllowThreads guard;
+        self.write_attributes_reply(id, timestamp);
+    }
+
+    static inline void write_attributes_reply(Tango::DeviceProxy& self, long id)
+    {
+        AutoPythonAllowThreads guard;
+        self.write_attributes_reply(id);
+    }
+
+    static inline void read_attributes_asynch(object py_self, object py_attr_names, object py_cb, PyTango::ExtractAs extract_as)
+    {
+        Tango::DeviceProxy* self = extract<Tango::DeviceProxy*>(py_self);
+        CSequenceFromPython<StdStringVector> attr_names(py_attr_names);
+
+        PyCallBackAutoDie* cb = extract<PyCallBackAutoDie*>(py_cb);
+        cb->set_autokill_references(py_cb, py_self);
+        cb->set_extract_as(extract_as);
+
+        try {
+            AutoPythonAllowThreads guard;
+            self->read_attributes_asynch(*attr_names, *cb);
+        } catch (...) {
+            cb->unset_autokill_references();
+            throw;
+        }
+    }
+
+    static inline void write_attributes_asynch(object py_self, object py_list, object py_cb)
+    {
+        Tango::DeviceProxy* self = extract<Tango::DeviceProxy*>(py_self);
+        std::vector<Tango::DeviceAttribute> dev_attrs;
+        pylist_to_devattrs(*self, py_list, dev_attrs);
+
+        PyCallBackAutoDie* cb = extract<PyCallBackAutoDie*>(py_cb);
+        cb->set_autokill_references(py_cb, py_self);
+
+        try {
+            AutoPythonAllowThreads guard;
+            self->write_attributes_asynch(dev_attrs, *cb);
+        } catch (...) {
+            cb->unset_autokill_references();
+            throw;
+        }
+    }
+
+    static int subscribe_event(
+            object py_self,
+            const string &attr_name,
+            Tango::EventType event,
+            object py_cb_or_queuesize,
+            object &py_filters,
+            bool stateless,
+            PyTango::ExtractAs extract_as )
+    {
+        Tango::DeviceProxy& self = extract<Tango::DeviceProxy&>(py_self);
+        CSequenceFromPython<StdStringVector> filters(py_filters);
+
+        PyCallBackPushEvent* cb = 0;
+        int event_queue_size = 0;
+        if (extract<PyCallBackPushEvent&>(py_cb_or_queuesize).check()) {
+            cb = extract<PyCallBackPushEvent*>(py_cb_or_queuesize);
+
+            cb->set_device(py_self);
+            cb->set_extract_as(extract_as);
+
+            AutoPythonAllowThreads guard;
+            return self.subscribe_event(attr_name, event, cb, *filters, stateless);
+        } else {
+            event_queue_size = extract<int>(py_cb_or_queuesize);
+            AutoPythonAllowThreads guard;
+            return self.subscribe_event(attr_name, event, event_queue_size, *filters, stateless);
+        }
+    }
+
+    static void unsubscribe_event(Tango::DeviceProxy& self, int event)
+    {
+        // If the callback is running, unsubscribe_event will lock
+        // until it finishes. So we MUST release GIL to avoid a deadlock
+        AutoPythonAllowThreads guard;
+        self.unsubscribe_event(event);
+    }
+
+    template<typename ED, typename EDList>
+    static object
+    get_events__aux(object py_self, int event_id, PyTango::ExtractAs extract_as=PyTango::ExtractAsNumpy)
+    {
+        Tango::DeviceProxy &self = extract<Tango::DeviceProxy&>(py_self);
+
+        EDList event_list;
+        self.get_events(event_id, event_list);
+
+        boost::python::list r;
+
+        for (size_t i=0; i < event_list.size(); ++i) {
+            ED* event_data = event_list[i];
+
+            object py_ev(handle<>(
+                            to_python_indirect<
+                                ED*,
+                                detail::make_owning_holder>()(event_data)));
+
+            // EventDataList deletes EventData's on destructor, so once
+            // we are handling it somewhere else (as an object) we must
+            // unset the reference
+            event_list[i] = 0;
+
+            PyCallBackPushEvent::fill_py_event(event_data, py_ev, py_self, extract_as);
+
+            r.append(py_ev);
+        }
+        return r;
+    }
+
+    static void
+    get_events__callback(object py_self, int event_id, PyCallBackPushEvent *cb, PyTango::ExtractAs extract_as)
+    {
+        Tango::DeviceProxy& self = extract<Tango::DeviceProxy&>(py_self);
+
+        cb->set_device(py_self);
+        cb->set_extract_as(extract_as);
+
+        self.get_events(event_id, cb);
+    }
+
+    static object
+    get_events__attr_conf(object py_self, int event_id)
+    {
+        return get_events__aux<Tango::AttrConfEventData, Tango::AttrConfEventDataList>
+                                                (py_self, event_id);
+    }
+
+    static object
+    get_events__data(object py_self, int event_id, PyTango::ExtractAs extract_as)
+    {
+        return get_events__aux<Tango::EventData, Tango::EventDataList>
+                                                (py_self, event_id, extract_as);
+    }
+
+    static object
+    get_events__data_ready(object py_self, int event_id)
+    {
+        return get_events__aux<Tango::DataReadyEventData, Tango::DataReadyEventDataList>
+                                                (py_self, event_id);
+    }
+};
+
+void export_device_proxy()
+{
+    // The following function declarations are necessary to be able to cast
+    // the function parameters from string& to const string&, otherwise python
+    // will not recognize the method calls
+
+    void (Tango::DeviceProxy::*get_property_)(std::string &, Tango::DbData &) =
+        &Tango::DeviceProxy::get_property;
+
+    void (Tango::DeviceProxy::*delete_property_)(std::string &) =
+        &Tango::DeviceProxy::delete_property;
+
+    class_<Tango::DeviceProxy, bases<Tango::Connection> > DeviceProxy(
+        "DeviceProxy",
+        init<>())
+    ;
+
+    DeviceProxy
+        .def(init<const char *>())
+        .def(init<const char *, bool>())
+        .def(init<const Tango::DeviceProxy &>())
+
+        //
+        // Pickle
+        //
+        .def_pickle(PyDeviceProxy::PickleSuite())
+
+        //
+        // general methods
+        //
+        .def("dev_name", &Tango::DeviceProxy::dev_name)
+        
+        .def("info", &Tango::DeviceProxy::info,
+            ( arg_("self") ),
+            return_internal_reference<1>() )
+
+        .def("get_device_db", &Tango::DeviceProxy::get_device_db,
+            return_value_policy<reference_existing_object>())
+
+        .def("status", &PyDeviceProxy::status,
+            ( arg_("self") ) )
+
+        .def("state", &PyDeviceProxy::state,
+            ( arg_("self") ) )
+
+        .def("adm_name", &Tango::DeviceProxy::adm_name,
+            ( arg_("self") ) )
+
+        .def("description", &Tango::DeviceProxy::description,
+            ( arg_("self") ) )
+
+        .def("name", &Tango::DeviceProxy::name,
+            ( arg_("self") ) )
+
+        .def("alias", &Tango::DeviceProxy::alias,
+            ( arg_("self") ) )
+
+        .def("ping", &PyDeviceProxy::ping,
+            ( arg_("self") ) )
+            
+
+        .def("black_box", &Tango::DeviceProxy::black_box,
+            ( arg_("self"), arg_("n") ),
+            return_value_policy<manage_new_object>() )
+
+        //
+        // device methods
+        //
+
+        .def("command_query", &Tango::DeviceProxy::command_query,
+            ( arg_("self"), arg_("command") ) )
+
+        .def("command_list_query", &Tango::DeviceProxy::command_list_query,
+            ( arg_("self") ),
+            return_value_policy<manage_new_object>() )
+
+        .def("import_info", &Tango::DeviceProxy::import_info,
+            ( arg_("self") ) )
+
+        //
+        // property methods
+        //
+        .def("_get_property",
+            (void (Tango::DeviceProxy::*) (const std::string &, Tango::DbData &))
+            get_property_,
+            ( arg_("self"), arg_("propname"), arg_("propdata") ) )
+
+        .def("_get_property",
+            (void (Tango::DeviceProxy::*) (std::vector<std::string>&, Tango::DbData &))
+            &Tango::DeviceProxy::get_property,
+            ( arg_("self"), arg_("propnames"), arg_("propdata") ) )
+
+        .def("_get_property",
+            (void (Tango::DeviceProxy::*) (Tango::DbData &))
+            &Tango::DeviceProxy::get_property,
+            ( arg_("self"), arg_("propdata") ) )
+
+        .def("_put_property", &Tango::DeviceProxy::put_property,
+            ( arg_("self"), arg_("propdata") ) )
+
+        .def("_delete_property", (void (Tango::DeviceProxy::*) (const std::string &))
+            delete_property_,
+            ( arg_("self"), arg_("propname") ) )
+
+        .def("_delete_property", (void (Tango::DeviceProxy::*) (StdStringVector &))
+            &Tango::DeviceProxy::delete_property,
+            ( arg_("self"), arg_("propnames") ) )
+
+        .def("_delete_property", (void (Tango::DeviceProxy::*) (Tango::DbData &))
+            &Tango::DeviceProxy::delete_property,
+            ( arg_("self"), arg_("propdata") ) )
+
+        .def("_get_property_list", &Tango::DeviceProxy::get_property_list,
+            ( arg_("self"), arg_("filter"), arg_("array") ) )
+
+        //
+        // attribute methods
+        //
+
+        .def("get_attribute_list", &Tango::DeviceProxy::get_attribute_list,
+            ( arg_("self") ),
+            return_value_policy<manage_new_object>() )
+
+        .def("_get_attribute_config",
+            (Tango::AttributeInfoList* (Tango::DeviceProxy::*)(StdStringVector &))
+            &Tango::DeviceProxy::get_attribute_config,
+            ( arg_("self"), arg_("attr_names") ),
+            return_value_policy<manage_new_object>() )
+
+        .def("_get_attribute_config",
+            (Tango::AttributeInfoEx (Tango::DeviceProxy::*)(const std::string&))
+            &Tango::DeviceProxy::get_attribute_config,
+            ( arg_("self"), arg_("attr_name") ) )
+
+        .def("_get_attribute_config_ex",
+            &Tango::DeviceProxy::get_attribute_config_ex,
+            ( arg_("self"), arg_("attr_names") ),
+            return_value_policy<manage_new_object>() )
+
+        .def("attribute_query", &Tango::DeviceProxy::attribute_query,
+            ( arg_("self"), arg_("attr_name") ) )
+
+        .def("attribute_list_query", &Tango::DeviceProxy::attribute_list_query,
+            ( arg_("self") ),
+            return_value_policy<manage_new_object>() )
+
+        .def("attribute_list_query_ex",
+            &Tango::DeviceProxy::attribute_list_query_ex,
+            ( arg_("self") ),
+            return_value_policy<manage_new_object>() )
+
+        .def("_set_attribute_config",
+            (void (Tango::DeviceProxy::*)(Tango::AttributeInfoList &))
+            &Tango::DeviceProxy::set_attribute_config,
+            ( arg_("self"), arg_("seq") ) )
+
+        .def("_set_attribute_config",
+            (void (Tango::DeviceProxy::*)(Tango::AttributeInfoListEx &))
+            &Tango::DeviceProxy::set_attribute_config,
+            ( arg_("self"), arg_("seq") ) )
+
+        .def("_read_attribute",
+            &PyDeviceProxy::read_attribute,
+            ( arg_("self"), arg_("attr_name"), arg_("extract_as")=PyTango::ExtractAsNumpy ) )
+
+        .def("read_attributes",
+            &PyDeviceProxy::read_attributes,
+            ( arg_("self"), arg_("attr_names"), arg_("extract_as")=PyTango::ExtractAsNumpy ) )
+
+        .def("write_attribute",
+            (void (*)(Tango::DeviceProxy&, const string &, object ))
+            &PyDeviceProxy::write_attribute,
+            ( arg_("self"), arg_("attr_name"), arg_("value") ) )
+
+        .def("write_attribute",
+            (void (*)(Tango::DeviceProxy&, const Tango::AttributeInfo &, object ))
+            &PyDeviceProxy::write_attribute,
+            ( arg_("self"), arg_("attr_info"), arg_("value") ) )
+
+        .def("write_attributes",
+            &PyDeviceProxy::write_attributes,
+            ( arg_("self"), arg_("name_val") ) )
+
+        .def("_write_read_attribute",
+            &PyDeviceProxy::write_read_attribute,
+            ( arg_("self"), arg_("attr_name"), arg_("value"), arg_("extract_as")=PyTango::ExtractAsNumpy ) )
+
+        //
+        // history methods
+        //
+
+        .def("command_history", &PyDeviceProxy::command_history,
+            (arg_("self"), arg_("cmd_name"), arg_("depth")),
+            return_value_policy<manage_new_object>() )
+
+        .def("attribute_history", &PyDeviceProxy::attribute_history,
+            (   arg_("self"),
+                arg_("attr_name"),
+                arg_("depth"),
+                arg_("extract_as")=PyTango::ExtractAsNumpy ) )
+
+        //
+        // Polling administration methods
+        //
+
+        .def("polling_status", &Tango::DeviceProxy::polling_status,
+            ( arg_("self") ),
+            return_value_policy<manage_new_object>() )
+
+        .def("poll_command",
+            (void (Tango::DeviceProxy::*)(const char *, int)) &Tango::DeviceProxy::poll_command,
+            ( arg_("self"), arg_("cmd_name"), arg_("period") ) )
+
+        .def("poll_attribute",
+            (void (Tango::DeviceProxy::*)(const char *, int)) &Tango::DeviceProxy::poll_attribute,
+            ( arg_("self"), arg_("attr_name"), arg_("period") ) )
+
+        .def("get_command_poll_period",
+            (int (Tango::DeviceProxy::*)(const char *)) &Tango::DeviceProxy::get_command_poll_period,
+            ( arg_("self"), arg_("cmd_name") ) )
+
+        .def("get_attribute_poll_period",
+            (int (Tango::DeviceProxy::*)(const char *)) &Tango::DeviceProxy::get_attribute_poll_period,
+            ( arg_("self"), arg_("attr_name") ) )
+
+        .def("is_command_polled",
+            (bool (Tango::DeviceProxy::*)(const char *)) &Tango::DeviceProxy::is_command_polled,
+            ( arg_("self"), arg_("cmd_name") ) )
+
+        .def("is_attribute_polled",
+            (bool (Tango::DeviceProxy::*)(const char *)) &Tango::DeviceProxy::is_attribute_polled,
+            ( arg_("self"), arg_("attr_name") ) )
+
+        .def("stop_poll_command",
+            (void (Tango::DeviceProxy::*)(const char *)) &Tango::DeviceProxy::stop_poll_command,
+            ( arg_("self"), arg_("cmd_name") ) )
+
+        .def("stop_poll_attribute",
+            (void (Tango::DeviceProxy::*)(const char *)) &Tango::DeviceProxy::stop_poll_attribute,
+            ( arg_("self"), arg_("attr_name") ) )
+
+        //
+        // Asynchronous methods
+        //
+        .def("__read_attributes_asynch",
+            (long (*) (Tango::DeviceProxy &, object))
+            &PyDeviceProxy::read_attributes_asynch,
+            ( arg_("self"), arg_("attr_names") ) )
+
+        .def("read_attributes_reply",
+            (object (*) (Tango::DeviceProxy &, long, PyTango::ExtractAs))
+            &PyDeviceProxy::read_attributes_reply,
+            ( arg_("self"), arg_("id"), arg_("extract_as")=PyTango::ExtractAsNumpy ) )
+
+        .def("read_attributes_reply",
+            (object (*) (Tango::DeviceProxy &, long, long, PyTango::ExtractAs))
+            &PyDeviceProxy::read_attributes_reply,
+            ( arg_("self"), arg_("id"), arg_("timeout"), arg_("extract_as")=PyTango::ExtractAsNumpy ) )
+
+        .def("pending_asynch_call",
+            &Tango::DeviceProxy::pending_asynch_call,
+            ( arg_("self"), arg_("req_type") ) )
+
+        .def("__write_attributes_asynch",
+            (long (*) (Tango::DeviceProxy &, object))
+            &PyDeviceProxy::write_attributes_asynch,
+            ( arg_("self"), arg_("values") ) )
+
+        .def("write_attributes_reply",
+            (void (*) (Tango::DeviceProxy &, long))
+            &PyDeviceProxy::write_attributes_reply,
+            ( arg_("self"), arg_("id") ) )
+
+        .def("write_attributes_reply",
+            (void (*) (Tango::DeviceProxy &, long, long))
+            &PyDeviceProxy::write_attributes_reply,
+            ( arg_("self"), arg_("id"), arg_("timeout") ) )
+
+        .def("__read_attributes_asynch",
+            (void (*) (object, object, object, PyTango::ExtractAs))
+            &PyDeviceProxy::read_attributes_asynch,
+            ( arg_("self"), arg_("attr_names"), arg_("callback"), arg_("extract_as")=PyTango::ExtractAsNumpy ) )
+
+        .def("__write_attributes_asynch",
+            (void (*) (object, object, object))
+            &PyDeviceProxy::write_attributes_asynch,
+            ( arg_("self"), arg_("values"), arg_("callback") ) )
+        
+        //
+        // Logging administration methods
+        //
+
+        .def("add_logging_target",
+            (void (Tango::DeviceProxy::*)(const std::string &)) &Tango::DeviceProxy::add_logging_target,
+            ( arg_("self"), arg_("target_type_target_name") ) )
+
+        .def("remove_logging_target",
+            (void (Tango::DeviceProxy::*)(const std::string &)) &Tango::DeviceProxy::remove_logging_target,
+            ( arg_("self"), arg_("target_type_target_name") ) )
+
+        .def("get_logging_target", &Tango::DeviceProxy::get_logging_target,
+            ( arg_("self") ) )
+
+        .def("get_logging_level", &Tango::DeviceProxy::get_logging_level,
+            ( arg_("self") ) )
+
+        .def("set_logging_level", &Tango::DeviceProxy::set_logging_level,
+            ( arg_("self"), arg_("level") ))
+
+        //
+        // Event methods
+        //
+
+        .def("__subscribe_event", &PyDeviceProxy::subscribe_event,
+            (   arg_("self"),
+                arg_("attr_name"),
+                arg_("event"),
+                arg_("cb_or_queuesize"),
+                arg_("filters")=boost::python::list(),
+                arg_("stateless")=false,
+                arg_("extract_as")=PyTango::ExtractAsNumpy )
+            )
+
+        .def("__unsubscribe_event", &PyDeviceProxy::unsubscribe_event )
+
+        .def("__get_callback_events", PyDeviceProxy::get_events__callback,
+            ( arg_("self"), arg_("event_id"), arg_("callback"), arg_("extract_as")=PyTango::ExtractAsNumpy) )
+
+        .def("__get_attr_conf_events", PyDeviceProxy::get_events__attr_conf,
+            ( arg_("self"), arg_("event_id")) )
+
+        .def("__get_data_events", PyDeviceProxy::get_events__data,
+            ( arg_("self"), arg_("event_id"), arg_("extract_as")=PyTango::ExtractAsNumpy ))
+
+        .def("__get_data_ready_events", PyDeviceProxy::get_events__data_ready,
+            ( arg_("self"), arg_("event_id")) )
+
+        // methods to access data in event queues
+        .def("event_queue_size", &Tango::DeviceProxy::event_queue_size,
+            ( arg_("self"), arg_("event_id") ) )
+
+        .def("get_last_event_date", &Tango::DeviceProxy::get_last_event_date,
+            ( arg_("self"), arg_("event_id") ) )
+
+        .def("is_event_queue_empty", &Tango::DeviceProxy::is_event_queue_empty,
+            ( arg_("self"), arg_("event_id") ) )
+
+        //
+        // Locking methods
+        //
+        .def("lock", &Tango::DeviceProxy::lock,
+            lock_overloads( ( arg_("lock_validity") )))
+
+        .def("unlock", &Tango::DeviceProxy::unlock,
+            unlock_overloads( arg_("force")))
+
+        .def("locking_status", &Tango::DeviceProxy::locking_status,
+            ( arg_("self") ))
+
+        .def("is_locked", &Tango::DeviceProxy::is_locked,
+            ( arg_("self") ))
+
+        .def("is_locked_by_me", &Tango::DeviceProxy::is_locked_by_me,
+            ( arg_("self") ))
+
+        .def("get_locker", &Tango::DeviceProxy::get_locker,
+            ( arg_("self"), arg_("lockinfo") ))
+
+        /// This is to be used by the python layer of this api...
+        //.setattr("__subscribed_events", boost::python::dict())
+        ;
+}
diff --git a/src/enums.cpp b/src/enums.cpp
new file mode 100644
index 0000000..4ae21cf
--- /dev/null
+++ b/src/enums.cpp
@@ -0,0 +1,230 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_enums()
+{
+    enum_<Tango::LockerLanguage>("LockerLanguage")
+        .value("CPP", Tango::CPP)
+        .value("JAVA", Tango::JAVA)
+    ;
+
+    enum_<Tango::CmdArgType>("CmdArgType")
+        .value(Tango::CmdArgTypeName[Tango::DEV_VOID], Tango::DEV_VOID)
+        .value(Tango::CmdArgTypeName[Tango::DEV_BOOLEAN], Tango::DEV_BOOLEAN)
+        .value(Tango::CmdArgTypeName[Tango::DEV_SHORT], Tango::DEV_SHORT)
+        .value(Tango::CmdArgTypeName[Tango::DEV_LONG], Tango::DEV_LONG)
+        .value(Tango::CmdArgTypeName[Tango::DEV_FLOAT], Tango::DEV_FLOAT)
+        .value(Tango::CmdArgTypeName[Tango::DEV_DOUBLE], Tango::DEV_DOUBLE)
+        .value(Tango::CmdArgTypeName[Tango::DEV_USHORT], Tango::DEV_USHORT)
+        .value(Tango::CmdArgTypeName[Tango::DEV_ULONG], Tango::DEV_ULONG)
+        .value(Tango::CmdArgTypeName[Tango::DEV_STRING], Tango::DEV_STRING)
+        .value(Tango::CmdArgTypeName[Tango::DEVVAR_CHARARRAY], Tango::DEVVAR_CHARARRAY)
+        .value(Tango::CmdArgTypeName[Tango::DEVVAR_SHORTARRAY], Tango::DEVVAR_SHORTARRAY)
+        .value(Tango::CmdArgTypeName[Tango::DEVVAR_LONGARRAY], Tango::DEVVAR_LONGARRAY)
+        .value(Tango::CmdArgTypeName[Tango::DEVVAR_FLOATARRAY], Tango::DEVVAR_FLOATARRAY)
+        .value(Tango::CmdArgTypeName[Tango::DEVVAR_DOUBLEARRAY], Tango::DEVVAR_DOUBLEARRAY)
+        .value(Tango::CmdArgTypeName[Tango::DEVVAR_USHORTARRAY], Tango::DEVVAR_USHORTARRAY)
+        .value(Tango::CmdArgTypeName[Tango::DEVVAR_ULONGARRAY], Tango::DEVVAR_ULONGARRAY)
+        .value(Tango::CmdArgTypeName[Tango::DEVVAR_STRINGARRAY], Tango::DEVVAR_STRINGARRAY)
+        .value(Tango::CmdArgTypeName[Tango::DEVVAR_LONGSTRINGARRAY], Tango::DEVVAR_LONGSTRINGARRAY)
+        .value(Tango::CmdArgTypeName[Tango::DEVVAR_DOUBLESTRINGARRAY], Tango::DEVVAR_DOUBLESTRINGARRAY)
+        .value(Tango::CmdArgTypeName[Tango::DEV_STATE], Tango::DEV_STATE)
+        .value(Tango::CmdArgTypeName[Tango::CONST_DEV_STRING], Tango::CONST_DEV_STRING)
+        .value(Tango::CmdArgTypeName[Tango::DEVVAR_BOOLEANARRAY], Tango::DEVVAR_BOOLEANARRAY)
+        .value(Tango::CmdArgTypeName[Tango::DEV_UCHAR], Tango::DEV_UCHAR)
+        .value(Tango::CmdArgTypeName[Tango::DEV_LONG64], Tango::DEV_LONG64)
+        .value(Tango::CmdArgTypeName[Tango::DEV_ULONG64], Tango::DEV_ULONG64)
+        .value(Tango::CmdArgTypeName[Tango::DEVVAR_LONG64ARRAY], Tango::DEVVAR_LONG64ARRAY)
+        .value(Tango::CmdArgTypeName[Tango::DEVVAR_ULONG64ARRAY], Tango::DEVVAR_ULONG64ARRAY)
+        .value(Tango::CmdArgTypeName[Tango::DEV_INT], Tango::DEV_INT)
+        .value("DevEncoded", Tango::DEV_ENCODED)
+        .export_values()
+    ;
+
+    enum_<Tango::MessBoxType>("MessBoxType")
+        .value("STOP", Tango::STOP)
+        .value("INFO", Tango::INFO)
+    ;
+
+    enum_<Tango::PollObjType>("PollObjType")
+        .value("POLL_CMD", Tango::POLL_CMD)
+        .value("POLL_ATTR", Tango::POLL_ATTR)
+        .value("EVENT_HEARTBEAT", Tango::EVENT_HEARTBEAT)
+        .value("STORE_SUBDEV", Tango::STORE_SUBDEV)
+    ;
+
+    enum_<Tango::PollCmdCode>("PollCmdCode")
+        .value("POLL_ADD_OBJ", Tango::POLL_ADD_OBJ)
+        .value("POLL_REM_OBJ", Tango::POLL_REM_OBJ)
+        .value("POLL_START", Tango::POLL_START)
+        .value("POLL_STOP", Tango::POLL_STOP)
+        .value("POLL_UPD_PERIOD", Tango::POLL_UPD_PERIOD)
+        .value("POLL_REM_DEV", Tango::POLL_REM_DEV)
+        .value("POLL_EXIT", Tango::POLL_EXIT)
+        .value("POLL_REM_EXT_TRIG_OBJ", Tango::POLL_REM_EXT_TRIG_OBJ)
+        .value("POLL_ADD_HEARTBEAT", Tango::POLL_ADD_HEARTBEAT)
+        .value("POLL_REM_HEARTBEAT", Tango::POLL_REM_HEARTBEAT)
+    ;
+
+    enum_<Tango::SerialModel>("SerialModel")
+        .value("BY_DEVICE",Tango::BY_DEVICE)
+        .value("BY_CLASS",Tango::BY_CLASS)
+        .value("BY_PROCESS",Tango::BY_PROCESS)
+        .value("NO_SYNC",Tango::NO_SYNC)
+    ;
+
+    enum_<Tango::AttReqType>("AttReqType")
+        .value("READ_REQ",Tango::READ_REQ)
+        .value("WRITE_REQ",Tango::WRITE_REQ)
+    ;
+
+    enum_<Tango::LockCmdCode>("LockCmdCode")
+        .value("LOCK_ADD_DEV", Tango::LOCK_ADD_DEV)
+        .value("LOCK_REM_DEV", Tango::LOCK_REM_DEV)
+        .value("LOCK_UNLOCK_ALL_EXIT", Tango::LOCK_UNLOCK_ALL_EXIT)
+        .value("LOCK_EXIT", Tango::LOCK_EXIT)
+    ;
+
+#ifdef TANGO_HAS_LOG4TANGO
+
+    enum_<Tango::LogLevel>("LogLevel")
+        .value("LOG_OFF", Tango::LOG_OFF)
+        .value("LOG_FATAL", Tango::LOG_FATAL)
+        .value("LOG_ERROR", Tango::LOG_ERROR)
+        .value("LOG_WARN", Tango::LOG_WARN)
+        .value("LOG_INFO", Tango::LOG_INFO)
+        .value("LOG_DEBUG", Tango::LOG_DEBUG)
+    ;
+
+    enum_<Tango::LogTarget>("LogTarget")
+        .value("LOG_CONSOLE", Tango::LOG_CONSOLE)
+        .value("LOG_FILE", Tango::LOG_FILE)
+        .value("LOG_DEVICE", Tango::LOG_DEVICE)
+    ;
+
+#endif // TANGO_HAS_LOG4TANGO
+
+    enum_<Tango::EventType>("EventType")
+        .value("CHANGE_EVENT", Tango::CHANGE_EVENT)
+        .value("QUALITY_EVENT", Tango::QUALITY_EVENT)
+        .value("PERIODIC_EVENT", Tango::PERIODIC_EVENT)
+        .value("ARCHIVE_EVENT", Tango::ARCHIVE_EVENT)
+        .value("USER_EVENT", Tango::USER_EVENT)
+        .value("ATTR_CONF_EVENT", Tango::ATTR_CONF_EVENT)
+        .value("DATA_READY_EVENT", Tango::DATA_READY_EVENT)
+    ;
+
+    enum_<Tango::AttrSerialModel>("AttrSerialModel")
+        .value("ATTR_NO_SYNC", Tango::ATTR_NO_SYNC)
+        .value("ATTR_BY_KERNEL", Tango::ATTR_BY_KERNEL)
+        .value("ATTR_BY_USER", Tango::ATTR_BY_USER)
+    ;
+    
+    enum_<Tango::KeepAliveCmdCode>("KeepAliveCmdCode")
+        .value("EXIT_TH", Tango::EXIT_TH)
+    ;
+
+    enum_<Tango::AccessControlType>("AccessControlType")
+        .value("ACCESS_READ", Tango::ACCESS_READ)
+        .value("ACCESS_WRITE", Tango::ACCESS_WRITE)
+    ;
+
+    enum_<Tango::asyn_req_type>("asyn_req_type")
+        .value("POLLING", Tango::POLLING)
+        .value("CALLBACK", Tango::CALL_BACK)
+        .value("ALL_ASYNCH", Tango::ALL_ASYNCH)
+    ;
+
+    enum_<Tango::cb_sub_model>("cb_sub_model")
+        .value("PUSH_CALLBACK", Tango::PUSH_CALLBACK)
+        .value("PULL_CALLBACK", Tango::PULL_CALLBACK)
+    ;
+
+    //
+    // Tango IDL
+    //
+
+    enum_<Tango::AttrQuality>("AttrQuality")
+        .value("ATTR_VALID", Tango::ATTR_VALID)
+        .value("ATTR_INVALID", Tango::ATTR_INVALID)
+        .value("ATTR_ALARM", Tango::ATTR_ALARM)
+        .value("ATTR_CHANGING", Tango::ATTR_CHANGING)
+        .value("ATTR_WARNING", Tango::ATTR_WARNING)
+    ;
+
+    enum_<Tango::AttrWriteType>("AttrWriteType")
+        .value("READ", Tango::READ)
+        .value("READ_WITH_WRITE", Tango::READ_WITH_WRITE)
+        .value("WRITE", Tango::WRITE)
+        .value("READ_WRITE", Tango::READ_WRITE)
+        .export_values()
+    ;
+
+    enum_<Tango::AttrDataFormat>("AttrDataFormat")
+        .value("SCALAR", Tango::SCALAR)
+        .value("SPECTRUM", Tango::SPECTRUM)
+        .value("IMAGE", Tango::IMAGE)
+        .value("FMT_UNKNOWN", Tango::FMT_UNKNOWN)
+        .export_values()
+    ;
+
+    enum_<Tango::DevSource>("DevSource")
+        .value("DEV", Tango::DEV)
+        .value("CACHE", Tango::CACHE)
+        .value("CACHE_DEV", Tango::CACHE_DEV)
+    ;
+
+    enum_<Tango::ErrSeverity>("ErrSeverity")
+        .value("WARN", Tango::WARN)
+        .value("ERR", Tango::ERR)
+        .value("PANIC", Tango::PANIC)
+    ;
+
+    enum_<Tango::DevState>("DevState")
+        .value(Tango::DevStateName[Tango::ON], Tango::ON)
+        .value(Tango::DevStateName[Tango::OFF], Tango::OFF)
+        .value(Tango::DevStateName[Tango::CLOSE], Tango::CLOSE)
+        .value(Tango::DevStateName[Tango::OPEN], Tango::OPEN)
+        .value(Tango::DevStateName[Tango::INSERT], Tango::INSERT)
+        .value(Tango::DevStateName[Tango::EXTRACT], Tango::EXTRACT)
+        .value(Tango::DevStateName[Tango::MOVING], Tango::MOVING)
+        .value(Tango::DevStateName[Tango::STANDBY], Tango::STANDBY)
+        .value(Tango::DevStateName[Tango::FAULT], Tango::FAULT)
+        .value(Tango::DevStateName[Tango::INIT], Tango::INIT)
+        .value(Tango::DevStateName[Tango::RUNNING], Tango::RUNNING)
+        .value(Tango::DevStateName[Tango::ALARM], Tango::ALARM)
+        .value(Tango::DevStateName[Tango::DISABLE], Tango::DISABLE)
+        .value(Tango::DevStateName[Tango::UNKNOWN], Tango::UNKNOWN)
+    ;
+
+    enum_<Tango::DispLevel>("DispLevel")
+        .value("OPERATOR", Tango::OPERATOR)
+        .value("EXPERT", Tango::EXPERT)
+    ;
+
+}
diff --git a/src/event_data.cpp b/src/event_data.cpp
new file mode 100644
index 0000000..b0fb084
--- /dev/null
+++ b/src/event_data.cpp
@@ -0,0 +1,59 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_event_data()
+{
+    class_<Tango::EventData>("EventData",
+        init<const Tango::EventData &>())
+    
+        // The original Tango::EventData structure has a 'device' field.
+        // However, if we returned this directly we would get a different
+        // python device each time. So we are doing our weird things to make
+        // sure the device returned is the same where the read action was
+        // performed. So we don't return Tango::EventData::device directly.
+        // See callback.cpp
+        .setattr("device", object())
+        
+        .def_readonly("attr_name", &Tango::EventData::attr_name)
+        .def_readonly("event", &Tango::EventData::event)
+        
+        // The original Tango::EventData structure has "get_attr_value" but
+        // we can't refer it directly here because we have to extract value
+        // and so on.
+        // See callback.cpp
+        .setattr("attr_value", object())
+        
+        .def_readonly("err", &Tango::EventData::err)
+        .def_readonly("reception_date", &Tango::EventData::reception_date)
+        .add_property("errors", make_getter(&Tango::EventData::errors, 
+            return_value_policy<copy_non_const_reference>()))
+        
+        .def("get_date", &Tango::EventData::get_date, 
+            return_internal_reference<>())
+    ;
+}
diff --git a/src/exception.cpp b/src/exception.cpp
new file mode 100644
index 0000000..0090959
--- /dev/null
+++ b/src/exception.cpp
@@ -0,0 +1,484 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+#include <tango.h>
+#include <iostream>
+#include <string>
+
+#include "pytgutils.h"
+
+using namespace boost::python;
+
+// Useful constants for exceptions
+
+const char *param_must_be_seq = "Parameter must be a string or a python "
+                                "sequence (e.x.: a tuple or a list)";
+
+const char *unreachable_code = "Code should be unreachable";
+
+const char *non_string_seq = "Parameter must be a non string sequence "
+                             "(e.x.: a tuple or a list)";
+
+const char *non_valid_image = "Parameter must be an IMAGE. This is a sequence"
+                              " of sequences (with all the sub-sequences having"
+                              " the same lenght) or a bidimensional numpy.array";
+
+const char *non_valid_spectrum = "Parameter must be an SPECTRUM. This is a"
+                              " sequence of scalar values or a unidimensional"
+                              " numpy.array";
+
+boost::python::object
+    PyTango_DevFailed,
+    PyTango_ConnectionFailed,
+    PyTango_CommunicationFailed,
+    PyTango_WrongNameSyntax,
+    PyTango_NonDbDevice,
+    PyTango_WrongData,
+    PyTango_NonSupportedFeature,
+    PyTango_AsynCall,
+    PyTango_AsynReplyNotArrived,
+    PyTango_EventSystemFailed,
+    PyTango_DeviceUnlocked,
+    PyTango_NotAllowed;
+
+namespace Tango
+{
+    inline bool operator==(const Tango::NamedDevFailed& df1, const Tango::NamedDevFailed& df2)
+    {
+        /// @todo ? err_stack ?
+        return (df1.name == df2.name) && (df1.idx_in_call == df2.idx_in_call);
+    }
+}
+
+void sequencePyDevError_2_DevErrorList(PyObject *value, Tango::DevErrorList &del)
+{
+    long len = max((int)PySequence_Size(value), 0);
+    del.length(len);
+
+    for (long loop = 0; loop < len; ++loop)
+    {
+        PyObject *item = PySequence_GetItem(value, loop);
+        Tango::DevError &dev_error = extract<Tango::DevError &>(item);
+        del[loop].desc = CORBA::string_dup(dev_error.desc);
+        del[loop].reason = CORBA::string_dup(dev_error.reason);
+        del[loop].origin = CORBA::string_dup(dev_error.origin);
+        del[loop].severity = dev_error.severity;
+        Py_XDECREF(item);
+    }
+}
+
+void PyDevFailed_2_DevFailed(PyObject *value, Tango::DevFailed &df)
+{
+    if (PyObject_IsInstance(value, PyTango_DevFailed.ptr()))
+    {
+        PyObject *args = PyObject_GetAttrString(value, "args");
+        if (PySequence_Check(args) == 0)
+        {
+            Py_XDECREF(args);
+
+            Tango::Except::throw_exception(
+                    (const char *)"PyDs_BadDevFailedException",
+                    (const char *)"A badly formed exception has been received",
+                    (const char *)"PyDevFailed_2_DevFailed");
+        }
+        else
+        {
+            sequencePyDevError_2_DevErrorList(args, df.errors);
+            Py_DECREF(args);
+        }
+    }
+    else
+    {
+        sequencePyDevError_2_DevErrorList(value, df.errors);
+    }
+}
+
+void throw_python_dev_failed()
+{
+    PyObject *type, *value, *traceback;
+    PyErr_Fetch(&type, &value, &traceback);
+
+    if (value == NULL)
+    {
+        Py_DECREF(type);
+        Py_XDECREF(traceback);
+
+        Tango::Except::throw_exception(
+                    (const char *)"PyDs_BadDevFailedException",
+                    (const char *)"A badly formed exception has been received",
+                    (const char *)"throw_python_dev_failed");
+    }
+
+    Tango::DevFailed df;
+    try
+    {
+        PyDevFailed_2_DevFailed(value, df);
+    }
+    catch(...)
+    {
+        Py_DECREF(type);
+        Py_DECREF(value);
+        Py_XDECREF(traceback);
+        throw;
+    }
+
+    Py_DECREF(type);
+    Py_DECREF(value);
+    Py_XDECREF(traceback);
+
+    throw df;
+}
+
+void throw_python_generic_exception()
+{
+    PyObject *type, *value, *traceback;
+    PyErr_Fetch(&type, &value, &traceback);
+
+//
+// Send a default exception in case Python does not send us information
+//
+    if (value == NULL)
+    {
+        Py_XDECREF(type);
+        Py_XDECREF(value);
+        Py_XDECREF(traceback);
+
+        Tango::Except::throw_exception((const char *)"PyDs_BadPythonException",
+                (const char *)"A badly formed exception has been received",
+                (const char *)"Py_throw_dev_failed");
+    }
+
+    Tango::DevErrorList dev_err;
+    dev_err.length(1);
+
+    //
+    // Populate a one level DevFailed exception
+    //
+
+    PyObject *tracebackModule = PyImport_ImportModule("traceback");
+    if (tracebackModule != NULL)
+    {
+        PyObject *tbList, *emptyString, *strRetval;
+
+        //
+        // Format the traceback part of the Python exception
+        // and store it in the origin part of the Tango exception
+        //
+
+        tbList = PyObject_CallMethod(
+                tracebackModule,
+                (char *)"format_tb",
+                (char *)"O",
+                traceback == NULL ? Py_None : traceback);
+
+        emptyString = PyString_FromString("");
+        strRetval = PyObject_CallMethod(emptyString, (char *)"join", (char *)"O", tbList);
+
+        dev_err[0].origin = CORBA::string_dup(PyString_AsString(strRetval));
+
+        Py_DECREF(tbList);
+        Py_DECREF(emptyString);
+        Py_DECREF(strRetval);
+
+        //
+        // Format the exec and value part of the Python exception
+        // and store it in the desc part of the Tango exception
+        //
+
+        tbList = PyObject_CallMethod(
+                tracebackModule,
+                (char *)"format_exception_only",
+                (char *)"OO",
+                type,
+                value == NULL ? Py_None : value);
+
+        emptyString = PyString_FromString("");
+        strRetval = PyObject_CallMethod(emptyString, (char *)"join", (char *)"O", tbList);
+
+        dev_err[0].desc = CORBA::string_dup(PyString_AsString(strRetval));
+
+        Py_DECREF(tbList);
+        Py_DECREF(emptyString);
+        Py_DECREF(strRetval);
+        Py_DECREF(tracebackModule);
+
+        dev_err[0].reason = CORBA::string_dup("PyDs_PythonError");
+        dev_err[0].severity = Tango::ERR;
+    }
+    else
+    {
+        //
+        // Send a default exception because we can't format the
+        // different parts of the Python's one !
+        //
+
+        dev_err[0].origin = CORBA::string_dup("Py_throw_dev_failed");
+        dev_err[0].desc = CORBA::string_dup("Can't import Python traceback module. Can't extract info from Python exception");
+        dev_err[0].reason = CORBA::string_dup("PyDs_PythonError");
+        dev_err[0].severity = Tango::ERR;
+    }
+
+    Py_XDECREF(type);
+    Py_XDECREF(value);
+    Py_XDECREF(traceback);
+
+    throw Tango::DevFailed(dev_err);
+}
+
+void handle_python_exception(boost::python::error_already_set &eas)
+{
+    if (PyErr_ExceptionMatches(PyTango_DevFailed.ptr()))
+    {
+        throw_python_dev_failed();
+    }
+    else
+    {
+        throw_python_generic_exception();
+    }
+}
+
+struct convert_PyDevFailed_to_DevFailed
+{
+    convert_PyDevFailed_to_DevFailed()
+    {
+        boost::python::converter::registry::push_back(
+            &convertible,
+            &construct,
+            boost::python::type_id<Tango::DevFailed>());
+    }
+
+    // Check if given Python object is convertible to a DevFailed.
+    // If so, return obj, otherwise return 0
+    static void* convertible(PyObject* obj)
+    {
+        if (PyObject_IsInstance(obj, PyTango_DevFailed.ptr()))
+            return obj;
+
+        return 0;
+    }
+
+    // Construct a vec3f object from the given Python object, and
+    // store it in the stage1 (?) data.
+    static void construct(PyObject* obj,
+                          boost::python::converter::rvalue_from_python_stage1_data* data)
+    {
+        typedef boost::python::converter::rvalue_from_python_storage<Tango::DevFailed> DevFailed_storage;
+
+        void* const storage = reinterpret_cast<DevFailed_storage*>(data)->storage.bytes;
+
+        Tango::DevFailed *df_ptr = new (storage) Tango::DevFailed();
+        PyDevFailed_2_DevFailed(obj, *df_ptr);
+        data->convertible = storage;
+    }
+};
+
+
+void _translate_dev_failed(const Tango::DevFailed &dev_failed,
+                           boost::python::object py_dev_failed)
+{
+    boost::python::object py_errors(dev_failed.errors);
+    PyErr_SetObject(py_dev_failed.ptr(), py_errors.ptr());
+}
+
+void translate_dev_failed(const Tango::DevFailed &dev_failed)
+{ _translate_dev_failed(dev_failed, PyTango_DevFailed); }
+
+void translate_connection_failed(const Tango::ConnectionFailed &dev_failed)
+{ _translate_dev_failed(dev_failed, PyTango_ConnectionFailed); }
+
+void translate_communication_failed(const Tango::CommunicationFailed &dev_failed)
+{ _translate_dev_failed(dev_failed, PyTango_CommunicationFailed); }
+
+void translate_wrong_name_syntax(const Tango::WrongNameSyntax &dev_failed)
+{ _translate_dev_failed(dev_failed, PyTango_WrongNameSyntax); }
+
+void translate_non_db_device(const Tango::NonDbDevice &dev_failed)
+{ _translate_dev_failed(dev_failed, PyTango_NonDbDevice); }
+
+void translate_wrong_data(const Tango::WrongData &dev_failed)
+{ _translate_dev_failed(dev_failed, PyTango_WrongData); }
+
+void translate_non_supported_feature(const Tango::NonSupportedFeature &dev_failed)
+{ _translate_dev_failed(dev_failed, PyTango_NonSupportedFeature); }
+
+void translate_asyn_call(const Tango::AsynCall &dev_failed)
+{ _translate_dev_failed(dev_failed, PyTango_AsynCall); }
+
+void translate_asyn_reply_not_arrived(const Tango::AsynReplyNotArrived &dev_failed)
+{ _translate_dev_failed(dev_failed, PyTango_AsynReplyNotArrived); }
+
+void translate_event_system_failed(const Tango::EventSystemFailed &dev_failed)
+{ _translate_dev_failed(dev_failed, PyTango_EventSystemFailed); }
+
+void translate_device_unlocked(const Tango::DeviceUnlocked &dev_failed)
+{ _translate_dev_failed(dev_failed, PyTango_DeviceUnlocked); }
+
+void translate_not_allowed(const Tango::NotAllowed &dev_failed)
+{ _translate_dev_failed(dev_failed, PyTango_NotAllowed); }
+
+namespace PyExcept
+{
+    inline void throw_exception(const char *a, const char *b, const char *c)
+    { Tango::Except::throw_exception(a, b, c); }
+
+    inline void throw_exception_severity(const char *a, const char *b, const char *c, Tango::ErrSeverity d)
+    { Tango::Except::throw_exception(a ,b, c, d); }
+
+    inline void re_throw_exception(const Tango::DevFailed &df, const char *a, const char *b, const char *c)
+    { Tango::Except::re_throw_exception(const_cast<Tango::DevFailed&>(df), a, b, c); }
+
+    inline void re_throw_exception_severity(const Tango::DevFailed &df, const char *a, const char *b, const char *c, Tango::ErrSeverity d)
+    { Tango::Except::re_throw_exception(const_cast<Tango::DevFailed&>(df), a, b, c, d); }
+
+    inline void print_exception(const Tango::DevFailed &df)
+    { Tango::Except::print_exception(df); }
+}
+
+namespace PyNamedDevFailed
+{
+    Tango::DevErrorList get_err_stack(Tango::NamedDevFailed & self)
+    {
+        return self.err_stack;
+    }
+}
+
+void export_exceptions()
+{
+    bool (*compare_exception_) (Tango::DevFailed &, Tango::DevFailed &) = &Tango::Except::compare_exception;
+
+    PyTango_DevFailed = boost::python::object(
+        boost::python::handle<>(PyErr_NewException(
+            (char *)"PyTango.DevFailed", NULL, NULL)));
+
+    PyObject *df_ptr = PyTango_DevFailed.ptr();
+
+    PyTango_ConnectionFailed = boost::python::object(
+        boost::python::handle<>(PyErr_NewException(
+            const_cast<char *>("PyTango.ConnectionFailed"), df_ptr, NULL)));
+    PyTango_CommunicationFailed = boost::python::object(
+        boost::python::handle<>(PyErr_NewException(
+            const_cast<char *>("PyTango.CommunicationFailed"), df_ptr, NULL)));
+    PyTango_WrongNameSyntax = boost::python::object(
+        boost::python::handle<>(PyErr_NewException(
+            const_cast<char *>("PyTango.WrongNameSyntax"), df_ptr, NULL)));
+    PyTango_NonDbDevice = boost::python::object(
+        boost::python::handle<>(PyErr_NewException(
+            const_cast<char *>("PyTango.NonDbDevice"), df_ptr, NULL)));
+    PyTango_WrongData = boost::python::object(
+        boost::python::handle<>(PyErr_NewException(
+            const_cast<char *>("PyTango.WrongData"), df_ptr, NULL)));
+    PyTango_NonSupportedFeature = boost::python::object(
+        boost::python::handle<>(PyErr_NewException(
+            const_cast<char *>("PyTango.NonSupportedFeature"), df_ptr, NULL)));
+    PyTango_AsynCall = boost::python::object(
+        boost::python::handle<>(PyErr_NewException(
+            const_cast<char *>("PyTango.AsynCall"), df_ptr, NULL)));
+    PyTango_AsynReplyNotArrived = boost::python::object(
+        boost::python::handle<>(PyErr_NewException(
+            const_cast<char *>("PyTango.AsynReplyNotArrived"), df_ptr, NULL)));
+    PyTango_EventSystemFailed = boost::python::object(
+        boost::python::handle<>(PyErr_NewException(
+            const_cast<char *>("PyTango.EventSystemFailed"), df_ptr, NULL)));
+    PyTango_DeviceUnlocked = boost::python::object(
+        boost::python::handle<>(PyErr_NewException(
+            const_cast<char *>("PyTango.DeviceUnlocked"), df_ptr, NULL)));
+    PyTango_NotAllowed = boost::python::object(
+        boost::python::handle<>(PyErr_NewException(
+            const_cast<char *>("PyTango.NotAllowed"), df_ptr, NULL)));
+
+    scope().attr("DevFailed") = PyTango_DevFailed;
+    scope().attr("ConnectionFailed") = PyTango_ConnectionFailed;
+    scope().attr("CommunicationFailed") = PyTango_CommunicationFailed;
+    scope().attr("WrongNameSyntax") = PyTango_WrongNameSyntax;
+    scope().attr("NonDbDevice") = PyTango_NonDbDevice;
+    scope().attr("WrongData") = PyTango_WrongData;
+    scope().attr("NonSupportedFeature") = PyTango_NonSupportedFeature;
+    scope().attr("AsynCall") = PyTango_AsynCall;
+    scope().attr("AsynReplyNotArrived") = PyTango_AsynReplyNotArrived;
+    scope().attr("EventSystemFailed") = PyTango_EventSystemFailed;
+    scope().attr("DeviceUnlocked") = PyTango_DeviceUnlocked;
+    scope().attr("NotAllowed") = PyTango_NotAllowed;
+
+    register_exception_translator<Tango::DevFailed>(&translate_dev_failed);
+    register_exception_translator<Tango::ConnectionFailed>(&translate_connection_failed);
+    register_exception_translator<Tango::CommunicationFailed>(&translate_communication_failed);
+    register_exception_translator<Tango::WrongNameSyntax>(&translate_wrong_name_syntax);
+    register_exception_translator<Tango::NonDbDevice>(&translate_non_db_device);
+    register_exception_translator<Tango::WrongData>(&translate_wrong_data);
+    register_exception_translator<Tango::NonSupportedFeature>(&translate_non_supported_feature);
+    register_exception_translator<Tango::AsynCall>(&translate_asyn_call);
+    register_exception_translator<Tango::AsynReplyNotArrived>(&translate_asyn_reply_not_arrived);
+    register_exception_translator<Tango::EventSystemFailed>(&translate_event_system_failed);
+    register_exception_translator<Tango::DeviceUnlocked>(&translate_device_unlocked);
+    register_exception_translator<Tango::NotAllowed>(&translate_not_allowed);
+
+    class_<Tango::Except,boost::noncopyable>("Except", no_init)
+        .def("throw_exception", &PyExcept::throw_exception)
+        .def("throw_exception", &PyExcept::throw_exception_severity)
+        .def("re_throw_exception", &PyExcept::re_throw_exception)
+        .def("re_throw_exception", &PyExcept::re_throw_exception_severity)
+        .def("print_exception", &PyExcept::print_exception)
+        .def("print_error_stack", &Tango::Except::print_error_stack)
+        .def("compare_exception",
+            (bool (*) (const Tango::DevFailed &, const Tango::DevFailed &))
+            compare_exception_)
+        .staticmethod("throw_exception")
+        .staticmethod("re_throw_exception")
+        .staticmethod("print_exception")
+        .staticmethod("print_error_stack")
+    ;
+
+    convert_PyDevFailed_to_DevFailed();
+
+    /// NamedDevFailed & family:
+    class_<Tango::NamedDevFailed> NamedDevFailed(
+        "NamedDevFailed",
+        "",
+        no_init)
+    ;
+    NamedDevFailed
+        .def_readonly("name", &Tango::NamedDevFailed::name) // string
+        .def_readonly("idx_in_call", &Tango::NamedDevFailed::idx_in_call) // long
+        .add_property("err_stack", PyNamedDevFailed::get_err_stack) // DevErrorList
+    ;
+
+    typedef std::vector<Tango::NamedDevFailed> StdNamedDevFailedVector_;
+    class_< StdNamedDevFailedVector_ >("StdNamedDevFailedVector")
+        .def(vector_indexing_suite<StdNamedDevFailedVector_>());
+
+    // DevFailed is not really exported but just translated, so we can't
+    // derivate.
+    class_<Tango::NamedDevFailedList/*, bases<Tango::DevFailed>*/ > NamedDevFailedList(
+        "NamedDevFailedList",
+        "",
+        no_init)
+    ;
+
+    NamedDevFailedList
+        .def("get_faulty_attr_nb", &Tango::NamedDevFailedList::get_faulty_attr_nb) // size_t
+        .def("call_failed", &Tango::NamedDevFailedList::call_failed) // bool
+        .def_readonly("err_list", &Tango::NamedDevFailedList::err_list) // vector<NamedDevFailed>
+    ;
+}
diff --git a/src/exception.h b/src/exception.h
new file mode 100644
index 0000000..cad258c
--- /dev/null
+++ b/src/exception.h
@@ -0,0 +1,104 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#pragma once
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+/**
+ * Translates a seq<DevError> into a C++ DevErrorList
+ *
+ * @param [in] seq a python sequence of DevError
+ * @param [out] err_list the object to be filled with the several DevError
+ */
+void sequencePyDevError_2_DevErrorList(PyObject *seq, Tango::DevErrorList &err_list);
+
+/**
+ * Translates a python DevFailed or a seq<DevError> into a C++ DevFailed
+ *
+ * @param [in] obj a python sequence of DevError or a DevFailed
+ * @param [out] df the object to be filled with the information extracted from obj
+ */
+void PyDevFailed_2_DevFailed(PyObject *obj, Tango::DevFailed &df);
+
+/**
+ * Throws the current python exception. Assumes the python err is set and contains
+ * a DevFailed exception
+ */
+void throw_python_dev_failed();
+
+/**
+ * Throws the current python exception as a DevFailed exception.
+ */
+void throw_python_generic_exception();
+
+/**
+ * Handles the current python exception:
+ * If a PyTango DevFaild -> translates it to C++ and throws the DevFailed
+ * If a generic python exception -> translates it to C++ DevFailed and throws the DevFailed
+ *
+ * @param[in] eas the boost python exception description (currently not used)
+ */
+void handle_python_exception(boost::python::error_already_set &eas);
+
+#define SAFE_CATCH_REPORT(meth_name) \
+    catch(boost::python::error_already_set &eas) \
+    { \
+        std::cerr << "PyTango generated an unexpected python exception in " \
+                  << meth_name << "." << std::endl \
+                  << "Please report this bug to PyTango with the following report:" \
+                  << std::endl; \
+        PyErr_Print(); \
+    } \
+    catch(Tango::DevFailed &df) \
+    { \
+        std::cerr << "PyTango generated a DevFailed exception in " \
+                  << meth_name << "." << std::endl \
+                  << "Please report this bug to PyTango with the following report:" \
+                  << std::endl; \
+        Tango::Except::print_exception(df); \
+    } \
+    catch(...) \
+    { \
+        std::cerr << "PyTango generated an unknown exception in " \
+                  << meth_name << "." << std::endl \
+                  << "Please report this bug to PyTango." << std::endl; \
+    }
+
+#define SAFE_CATCH_INFORM(meth_name) \
+    catch(boost::python::error_already_set &eas) \
+    { \
+        std::cerr << meth_name << " generated the following python exception:" << std::endl; \
+        PyErr_Print(); \
+    } \
+    catch(Tango::DevFailed &df) \
+    { \
+        std::cerr << meth_name << " generated the following DevFailed exception:" << std::endl; \
+        Tango::Except::print_exception(df); \
+    } \
+    catch(...) \
+    { \
+        std::cerr << meth_name << " generated an unknown exception." << std::endl; \
+    }
+
diff --git a/src/fast_from_py.h b/src/fast_from_py.h
new file mode 100644
index 0000000..6e66ccb
--- /dev/null
+++ b/src/fast_from_py.h
@@ -0,0 +1,705 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#pragma once
+
+#include "from_py.h"
+
+/**
+ * Translation between python object to Tango data type.
+ *
+ * Example:
+ * Tango::DevLong tg_value;
+ * try
+ * {
+ *     from_py<Tango::DEV_LONG>::convert(py_obj, tg_value);
+ * }
+ * catch(boost::python::error_already_set &eas)
+ * {
+ *     handle_error(eas);
+ * }
+ */
+template<long tangoTypeConst>
+struct from_py
+{
+    typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+
+    static inline void convert(const boost::python::object &o, TangoScalarType &tg)
+    {
+        convert(o.ptr(), tg);
+    }
+
+    static inline void convert(PyObject *o, TangoScalarType &tg)
+    {
+        // boost::python::object tmp(boost::python::handle<>(o));
+        // tg = boost::python::extract<TangoScalartype>(tmp);
+        Tango::Except::throw_exception( \
+                        "PyDs_WrongPythonDataTypeForAttribute",
+                        "Unsupported attribute type translation",
+                        "from_py::convert()");
+    }
+};
+
+#define DEFINE_FAST_TANGO_FROMPY(tangoTypeConst, FN) \
+template<> \
+struct from_py<tangoTypeConst> \
+{ \
+    typedef TANGO_const2type(tangoTypeConst) TangoScalarType; \
+\
+    static inline void convert(const boost::python::object &o, TangoScalarType &tg) \
+    { \
+        convert(o.ptr(), tg); \
+    } \
+\
+    static inline void convert(PyObject *o, TangoScalarType &tg) \
+    { \
+        tg = static_cast<TangoScalarType>(FN(o));  \
+        if(PyErr_Occurred()) \
+            boost::python::throw_error_already_set();  \
+    } \
+};
+
+#undef max 
+#undef min
+
+// DEFINE_FAST_TANGO_FROMPY should be enough. However, as python does not
+// provide conversion from python integers to all the data types accepted
+// by tango we must check the ranges manually. Also now we can add numpy
+// support to some extent...
+#ifdef DISABLE_PYTANGO_NUMPY
+# define DEFINE_FAST_TANGO_FROMPY_NUM(tangoTypeConst, cpy_type, FN) \
+    template<> \
+    struct from_py<tangoTypeConst> \
+    { \
+        typedef TANGO_const2type(tangoTypeConst) TangoScalarType; \
+        typedef numeric_limits<TangoScalarType> TangoScalarTypeLimits; \
+    \
+        static inline void convert(const boost::python::object &o, TangoScalarType &tg) \
+        { \
+            convert(o.ptr(), tg); \
+        } \
+    \
+        static inline void convert(PyObject *o, TangoScalarType &tg) \
+        { \
+            cpy_type cpy_value = FN(o); \
+            if(PyErr_Occurred()) { \
+                PyErr_SetString(PyExc_TypeError, "Expecting a numeric type, it is not."); \
+                boost::python::throw_error_already_set();  \
+            } \
+            if (cpy_value > TangoScalarTypeLimits::max()) { \
+                PyErr_SetString(PyExc_OverflowError, "Value is too large."); \
+                boost::python::throw_error_already_set(); \
+            } \
+            if (cpy_value < TangoScalarTypeLimits::min()) { \
+                PyErr_SetString(PyExc_OverflowError, "Value is too small."); \
+                boost::python::throw_error_already_set(); \
+            } \
+            \
+            tg = static_cast<TangoScalarType>(cpy_value);  \
+        } \
+    };
+#else // DISABLE_PYTANGO_NUMPY
+# define DEFINE_FAST_TANGO_FROMPY_NUM(tangoTypeConst, cpy_type, FN) \
+    template<> \
+    struct from_py<tangoTypeConst> \
+    { \
+        typedef TANGO_const2type(tangoTypeConst) TangoScalarType; \
+        typedef numeric_limits<TangoScalarType> TangoScalarTypeLimits; \
+    \
+        static inline void convert(const boost::python::object &o, TangoScalarType &tg) \
+        { \
+            convert(o.ptr(), tg); \
+        } \
+    \
+        static inline void convert(PyObject *o, TangoScalarType &tg) \
+        { \
+            cpy_type cpy_value = FN(o); \
+            if(PyErr_Occurred()) { \
+                if(PyArray_CheckScalar(o) && \
+                ( PyArray_DescrFromScalar(o) \
+                    == PyArray_DescrFromType(TANGO_const2numpy(tangoTypeConst)))) \
+                { \
+                    PyArray_ScalarAsCtype(o, reinterpret_cast<void*>(&tg)); \
+                    return; \
+                } else \
+                    PyErr_SetString(PyExc_TypeError, "Expecting a numeric type," \
+                        " but it is not. If you use a numpy type instead of" \
+                        " python core types, then it must exactly match (ex:" \
+                        " numpy.int32 for PyTango.DevLong)"); \
+                    boost::python::throw_error_already_set();  \
+            } \
+            if (TangoScalarTypeLimits::is_integer) { \
+                if (cpy_value > TangoScalarTypeLimits::max()) { \
+                    PyErr_SetString(PyExc_OverflowError, "Value is too large."); \
+                    boost::python::throw_error_already_set(); \
+                } \
+                if (cpy_value < TangoScalarTypeLimits::min()) { \
+                    PyErr_SetString(PyExc_OverflowError, "Value is too small."); \
+                    boost::python::throw_error_already_set(); \
+                } \
+            } \
+            tg = static_cast<TangoScalarType>(cpy_value);  \
+        } \
+    };
+#endif // !DISABLE_PYTANGO_NUMPY
+
+DEFINE_FAST_TANGO_FROMPY_NUM(Tango::DEV_BOOLEAN, long, PyLong_AsLong)
+DEFINE_FAST_TANGO_FROMPY_NUM(Tango::DEV_UCHAR, unsigned long, PyLong_AsUnsignedLong)
+DEFINE_FAST_TANGO_FROMPY_NUM(Tango::DEV_SHORT, long, PyLong_AsLong)
+DEFINE_FAST_TANGO_FROMPY_NUM(Tango::DEV_USHORT, unsigned long, PyLong_AsUnsignedLong)
+DEFINE_FAST_TANGO_FROMPY_NUM(Tango::DEV_LONG, long, PyLong_AsLong)
+DEFINE_FAST_TANGO_FROMPY_NUM(Tango::DEV_ULONG, unsigned long, PyLong_AsUnsignedLong)
+DEFINE_FAST_TANGO_FROMPY(Tango::DEV_STATE, PyLong_AsLong)
+
+DEFINE_FAST_TANGO_FROMPY_NUM(Tango::DEV_LONG64, Tango::DevLong64, PyLong_AsLongLong)
+DEFINE_FAST_TANGO_FROMPY_NUM(Tango::DEV_ULONG64, Tango::DevULong64, PyLong_AsUnsignedLongLong)
+DEFINE_FAST_TANGO_FROMPY_NUM(Tango::DEV_FLOAT, double, PyFloat_AsDouble)
+DEFINE_FAST_TANGO_FROMPY_NUM(Tango::DEV_DOUBLE, double, PyFloat_AsDouble)
+
+/// @bug Not a bug per se, but you should keep in mind: It returns a new
+/// string, so if you pass it to Tango with a release flag there will be
+/// no problems, but if you have to use it yourself then you must remember
+/// to delete[] it!
+inline Tango::DevString PyString_AsCorbaString(PyObject* ob)
+{
+    const char* str = PyString_AsString(ob);
+    if (!str)
+        return 0;
+    return CORBA::string_dup(str);
+}
+
+// DEFINE_FAST_TANGO_FROMPY(Tango::DEV_STRING, PyString_AsString)
+DEFINE_FAST_TANGO_FROMPY(Tango::DEV_STRING, PyString_AsCorbaString)
+
+
+template<long tangoArrayTypeConst>
+struct array_element_from_py : public from_py<TANGO_const2scalarconst(tangoArrayTypeConst)>
+{ };
+
+template<>
+struct array_element_from_py<Tango::DEVVAR_CHARARRAY>
+{
+    static const long tangoArrayTypeConst = Tango::DEVVAR_CHARARRAY;
+
+    typedef TANGO_const2scalartype(tangoArrayTypeConst) TangoScalarType;
+    typedef numeric_limits<TangoScalarType> TangoScalarTypeLimits;
+
+    static inline void convert(const boost::python::object &o, TangoScalarType &tg)
+    {
+        convert(o.ptr(), tg);
+    }
+
+    static inline void convert(PyObject *o, TangoScalarType &tg)
+    {
+        long cpy_value = PyLong_AsLong(o);
+        if(PyErr_Occurred()) {
+            if(PyArray_CheckScalar(o) &&
+            ( PyArray_DescrFromScalar(o)
+                == PyArray_DescrFromType(TANGO_const2scalarnumpy(tangoArrayTypeConst))))
+            {
+                PyArray_ScalarAsCtype(o, reinterpret_cast<void*>(&tg));
+                return;
+            } else
+                PyErr_SetString(PyExc_TypeError, "Expecting a numeric type,"
+                    " but it is not. If you use a numpy type instead of"
+                    " python core types, then it must exactly match (ex:"
+                    " numpy.int32 for PyTango.DevLong)");
+                boost::python::throw_error_already_set(); 
+        }
+        if (TangoScalarTypeLimits::is_integer) {
+            if (cpy_value > TangoScalarTypeLimits::max()) {
+                PyErr_SetString(PyExc_OverflowError, "Value is too large.");
+                boost::python::throw_error_already_set();
+            }
+            if (cpy_value < TangoScalarTypeLimits::min()) {
+                PyErr_SetString(PyExc_OverflowError, "Value is too small.");
+                boost::python::throw_error_already_set();
+            }
+        }
+        tg = static_cast<TangoScalarType>(cpy_value);
+    }
+};
+
+
+template<long tangoTypeConst>
+inline void fast_python_to_tango_buffer_deleter__(typename TANGO_const2type(tangoTypeConst)* data_buffer, long processedElements)
+{
+    delete [] data_buffer;
+}
+
+template<>
+inline void fast_python_to_tango_buffer_deleter__<Tango::DEV_STRING>(Tango::DevString* data_buffer, long processedElements)
+{
+    for (long i =0; i < processedElements; ++i) {
+        delete [] data_buffer[i];
+    }
+    delete [] data_buffer;
+}
+
+template<long tangoTypeConst>
+inline typename TANGO_const2type(tangoTypeConst)*
+    fast_python_to_tango_buffer_sequence(PyObject* py_val, long* pdim_x, long *pdim_y, const std::string &fname, bool isImage, long& res_dim_x, long& res_dim_y)
+{
+    typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+    typedef typename TANGO_const2arraytype(tangoTypeConst) TangoArrayType;
+
+    long dim_x;
+    long dim_y = 0;
+    long len = PySequence_Size(py_val);
+    bool expectFlatSource;
+
+    if (isImage) {
+        if (pdim_y) {
+            expectFlatSource = true;
+            dim_x = *pdim_x;
+            dim_y = *pdim_y;
+            long len2 = dim_x*dim_y;
+            if (len2 < len)
+                len = len2;
+        } else {
+            expectFlatSource = false;
+
+            if (len > 0) {
+                PyObject* py_row0 = PySequence_ITEM(py_val, 0);
+                if (!py_row0 || !PySequence_Check(py_row0)) {
+                    Py_XDECREF(py_row0);
+                    Tango::Except::throw_exception(
+                        "PyDs_WrongParameters",
+                        "Expecting a sequence of sequences.",
+                        fname + "()");
+                }
+
+                dim_y = len;
+                dim_x = PySequence_Size(py_row0);
+                Py_XDECREF(py_row0);
+            } else {
+                dim_x = 0;
+            }
+        }
+        len = dim_x*dim_y;
+    } else {
+        expectFlatSource = true;
+        if (pdim_x) {
+            if (*pdim_x > len)
+                Tango::Except::throw_exception(
+                    "PyDs_WrongParameters",
+                    "Specified dim_x is larger than the sequence size",
+                    fname + "()");
+            len = *pdim_x;
+        }
+        if (pdim_y && (*pdim_y!=0))
+            Tango::Except::throw_exception(
+                    "PyDs_WrongParameters",
+                    "You should not specify dim_y for an spectrum attribute!",
+                    fname + "()");
+        dim_x = len;
+    }
+
+    res_dim_x = dim_x;
+    res_dim_y = dim_y;
+
+    if (!PySequence_Check(py_val))
+        Tango::Except::throw_exception(
+            "PyDs_WrongParameters",
+            "Expecting a sequence!",
+            fname + "()");
+
+    /// @bug Why not TangoArrayType::allocbuf(len)? Because
+    /// I will use it in set_value(tg_ptr,...,release=true).
+    /// Tango API makes delete[] tg_ptr instead of freebuf(tg_ptr).
+    /// This is usually the same, but for Tango::DevStringArray the
+    /// behaviour seems different and causes weirdtroubles..
+    TangoScalarType *tg_ptr;
+    tg_ptr = new TangoScalarType[len];
+
+    // The boost extract could be used:
+    // TangoScalarType val = boost::python::extract<TangoScalarType>(elt_ptr);
+    // instead of the code below.
+    // the problem is that extract is considerably slower than our
+    // convert function which only has to deal with the specific tango
+    // data types
+
+    PyObject * py_el = 0;
+    PyObject * py_row = 0;
+    TangoScalarType tg_scalar;
+    long idx = 0;
+    try {
+        if (expectFlatSource) {
+            for (idx = 0; idx < len; ++idx)
+            {
+                py_el = PySequence_ITEM(py_val, idx);
+                if (!py_el)
+                        boost::python::throw_error_already_set();
+                
+                from_py<tangoTypeConst>::convert(py_el, tg_scalar);
+                tg_ptr[idx] = tg_scalar;
+                
+                Py_DECREF(py_el);
+                py_el = 0;
+            }
+        } else {
+            for (long y=0; y < dim_y; ++y) {
+                py_row = PySequence_ITEM(py_val, y);
+                if (!py_row)
+                        boost::python::throw_error_already_set();
+                if (!PySequence_Check(py_row)) {
+                    Tango::Except::throw_exception(
+                        "PyDs_WrongParameters",
+                        "Expecting a sequence of sequences!",
+                        fname + "()");
+                }
+                for (long x=0; x < dim_x; ++x, ++idx) {
+                    py_el = PySequence_ITEM(py_row, x);
+                    if (!py_el)
+                        boost::python::throw_error_already_set();
+                    
+                    from_py<tangoTypeConst>::convert(py_el, tg_scalar);
+                    tg_ptr[x + y*dim_x] = tg_scalar;
+                    
+                    Py_DECREF(py_el);
+                    py_el = 0;
+                }
+                Py_DECREF(py_row);
+                py_row = 0;
+            }
+        }
+    } catch(...) {
+        Py_XDECREF(py_el);
+        Py_XDECREF(py_row);
+        fast_python_to_tango_buffer_deleter__<tangoTypeConst>(tg_ptr, idx);
+        throw;
+    }
+    return tg_ptr;
+}
+
+/*
+template<>
+inline Tango::DevString*
+    fast_python_to_tango_buffer_sequence<Tango::DEV_STRING>(PyObject* py_val, long* pdim_x, long *pdim_y, const std::string &fname, bool isImage, long& res_dim_x, long& res_dim_y)
+{
+    long dim_x;
+    long dim_y = 0;
+    long len = PySequence_Size(py_val);
+    bool expectFlatSource;
+
+    if (isImage) {
+        if (pdim_y) {
+            expectFlatSource = true;
+            dim_x = *pdim_x;
+            dim_y = *pdim_y;
+            long len2 = dim_x*dim_y;
+            if (len2 < len)
+                len = len2;
+        } else {
+            expectFlatSource = false;
+
+            if (len > 0) {
+                PyObject* py_row0 = PySequence_ITEM(py_val, 0);
+                if (!py_row0 || !PySequence_Check(py_row0)) {
+                    Py_XDECREF(py_row0);
+                    Tango::Except::throw_exception(
+                        "PyDs_WrongParameters",
+                        "Expecting a sequence of sequences.",
+                        fname + "()");
+                }
+
+                dim_y = len;
+                dim_x = PySequence_Size(py_row0);
+                Py_XDECREF(py_row0);
+            } else {
+                dim_x = 0;
+            }
+        }
+        len = dim_x*dim_y;
+    } else {
+        expectFlatSource = true;
+        if (pdim_x) {
+            if (*pdim_x > len)
+                Tango::Except::throw_exception(
+                    "PyDs_WrongParameters",
+                    "Specified dim_x is larger than the sequence size",
+                    fname + "()");
+            len = *pdim_x;
+        }
+        if (pdim_y && (*pdim_y!=0))
+            Tango::Except::throw_exception(
+                    "PyDs_WrongParameters",
+                    "You should not specify dim_y for an spectrum attribute!",
+                    fname + "()");
+        dim_x = len;
+    }
+
+    res_dim_x = dim_x;
+    res_dim_y = dim_y;
+
+    if (!PySequence_Check(py_val))
+        Tango::Except::throw_exception(
+            "PyDs_WrongParameters",
+            "Expecting a sequence!",
+            fname + "()");
+
+    /// @bug Why not TangoArrayType::allocbuf(len)? Because
+    /// I will use it in set_value(tg_ptr,...,release=true).
+    /// Tango API makes delete[] tg_ptr instead of freebuf(tg_ptr).
+    /// This is usually the same, but for Tango::DevStringArray the
+    /// behaviour seems different and causes weirdtroubles..
+    Tango::DevString *tg_ptr;
+    tg_ptr = new Tango::DevString[len];
+
+    // The boost extract could be used:
+    // TangoScalarType val = boost::python::extract<TangoScalarType>(elt_ptr);
+    // instead of the code below.
+    // the problem is that extract is considerably slower than our
+    // convert function which only has to deal with the specific tango
+    // data types
+
+    PyObject * py_el = 0;
+    PyObject * py_row = 0;
+    Tango::DevString tg_scalar;
+    long idx = 0;
+    try {
+        if (expectFlatSource) {
+            for (idx = 0; idx < len; ++idx)
+            {
+                py_el = PySequence_ITEM(py_val, idx);
+                if (!py_el)
+                        boost::python::throw_error_already_set();
+                
+                tg_scalar = PyString_AsString(py_el);
+                tg_ptr[idx] = tg_scalar;
+                
+                Py_DECREF(py_el);
+                py_el = 0;
+            }
+        } else {
+            for (long y=0; y < dim_y; ++y) {
+                py_row = PySequence_ITEM(py_val, y);
+                if (!py_row)
+                        boost::python::throw_error_already_set();
+                if (!PySequence_Check(py_row)) {
+                    Tango::Except::throw_exception(
+                        "PyDs_WrongParameters",
+                        "Expecting a sequence of sequences!",
+                        fname + "()");
+                }
+                for (long x=0; x < dim_x; ++x, ++idx) {
+                    py_el = PySequence_ITEM(py_row, x);
+                    if (!py_el)
+                        boost::python::throw_error_already_set();
+                    
+                    tg_scalar = PyString_AsString(py_el);
+                    tg_ptr[x + y*dim_x] = tg_scalar;
+                    
+                    Py_DECREF(py_el);
+                    py_el = 0;
+                }
+                Py_DECREF(py_row);
+                py_row = 0;
+            }
+        }
+    } catch(...) {
+        Py_XDECREF(py_el);
+        Py_XDECREF(py_row);
+        fast_python_to_tango_buffer_deleter__<Tango::DEV_STRING>(tg_ptr, idx);
+        throw;
+    }
+    return tg_ptr;
+}
+*/
+
+template<long tangoArrayTypeConst>
+inline typename TANGO_const2scalartype(tangoArrayTypeConst)*
+    fast_python_to_corba_buffer_sequence(PyObject* py_val, long* pdim_x, const std::string &fname, long& res_dim_x)
+{
+    typedef typename TANGO_const2type(tangoArrayTypeConst) TangoArrayType;
+    typedef typename TANGO_const2scalartype(tangoArrayTypeConst) TangoScalarType;
+
+    long dim_x;
+    long len = PySequence_Size(py_val);
+
+    if (pdim_x) {
+        if (*pdim_x > len)
+            Tango::Except::throw_exception(
+                "PyDs_WrongParameters",
+                "Specified dim_x is larger than the sequence size",
+                fname + "()");
+        len = *pdim_x;
+    }
+    dim_x = len;
+
+    res_dim_x = dim_x;
+
+    if (!PySequence_Check(py_val))
+        Tango::Except::throw_exception(
+            "PyDs_WrongParameters",
+            "Expecting a sequence!",
+            fname + "()");
+
+     TangoScalarType* tg_ptr = TangoArrayType::allocbuf(len);
+
+    // The boost extract could be used:
+    // TangoScalarType val = boost::python::extract<TangoScalarType>(elt_ptr);
+    // instead of the code below.
+    // the problem is that extract is considerably slower than our
+    // convert function which only has to deal with the specific tango
+    // data types
+
+    PyObject * py_el = 0;
+    TangoScalarType tg_scalar;
+    long idx = 0;
+    try {
+        for (idx = 0; idx < len; ++idx)
+        {
+            py_el = PySequence_ITEM(py_val, idx);
+            if (!py_el)
+                    boost::python::throw_error_already_set();
+
+            array_element_from_py<tangoArrayTypeConst>::convert(py_el, tg_scalar);
+            tg_ptr[idx] = tg_scalar;
+            
+            Py_DECREF(py_el);
+            py_el = 0;
+        }
+    } catch(...) {
+        Py_XDECREF(py_el);
+        TangoArrayType::freebuf(tg_ptr);
+        throw;
+    }
+    return tg_ptr;
+}
+
+template<>
+inline TANGO_const2type(Tango::DEV_ENCODED)*
+    fast_python_to_tango_buffer_sequence<Tango::DEV_ENCODED>(PyObject*, long*, long*, const std::string & fname, bool isImage, long& res_dim_x, long& res_dim_y)
+{
+    TangoSys_OMemStream o;
+    o << "DevEncoded is only supported for SCALAR attributes." << ends;
+    Tango::Except::throw_exception(
+            "PyDs_WrongPythonDataTypeForAttribute",
+            o.str(), fname + "()");
+    return 0;
+}
+
+# ifndef DISABLE_PYTANGO_NUMPY
+#   include "fast_from_py_numpy.hpp"
+#   define fast_python_to_tango_buffer fast_python_to_tango_buffer_numpy
+#   define fast_python_to_corba_buffer fast_python_to_corba_buffer_numpy
+# else
+#   define fast_python_to_tango_buffer fast_python_to_tango_buffer_sequence
+#   define fast_python_to_corba_buffer fast_python_to_corba_buffer_sequence
+# endif
+
+template<long tangoArrayTypeConst>
+inline typename TANGO_const2type(tangoArrayTypeConst)* fast_convert2array(boost::python::object o)
+{
+    typedef typename TANGO_const2type(tangoArrayTypeConst) TangoArrayType;
+    typedef typename TANGO_const2scalartype(tangoArrayTypeConst) TangoScalarType;
+
+    long res_dim_x;
+    
+    // Last parameter false: destruction will be handled by CORBA, not by
+    // Tango. So, when we destroy it manually later, we also have to use the
+    // CORBA style (TangoArrayType are defines by CORBA idl)
+    TangoScalarType* array = fast_python_to_corba_buffer<tangoArrayTypeConst>(o.ptr(), 0, "insert_array", res_dim_x);
+
+    try {
+        // not a bug: res_dim_y means nothing to us, we are unidimensional
+        // here we have max_len and currebt_len = res_dim_x
+        return new TangoArrayType(res_dim_x, res_dim_x, array, true);
+    } catch(...) {
+        TangoArrayType::freebuf(array);
+        throw;
+    }
+    return 0;
+}
+
+template<>
+inline TANGO_const2type(Tango::DEVVAR_LONGSTRINGARRAY)* fast_convert2array<Tango::DEVVAR_LONGSTRINGARRAY>(boost::python::object py_value)
+{
+    const long tangoArrayTypeConst = Tango::DEVVAR_LONGSTRINGARRAY;
+    typedef TANGO_const2type(tangoArrayTypeConst) TangoArrayType;
+
+    if (!PySequence_Check(py_value.ptr()))
+    {
+        raise_convert2array_DevVarLongStringArray();
+    }
+    
+    size_t size = boost::python::len(py_value);
+    if (size != 2)
+    {
+        raise_convert2array_DevVarLongStringArray();
+    }
+    
+    const boost::python::object
+        &py_lng = py_value[0],
+        &py_str = py_value[1];
+
+    std::auto_ptr<Tango::DevVarLongArray> a_lng(
+        fast_convert2array<Tango::DEVVAR_LONGARRAY>(py_lng));
+
+    std::auto_ptr<Tango::DevVarStringArray> a_str(
+        fast_convert2array<Tango::DEVVAR_STRINGARRAY>(py_str));
+
+    std::auto_ptr<TangoArrayType> result(new TangoArrayType());
+
+    result->lvalue = *a_lng;
+    result->svalue = *a_str;
+
+    return result.release();
+}
+
+template<>
+inline TANGO_const2type(Tango::DEVVAR_DOUBLESTRINGARRAY)* fast_convert2array<Tango::DEVVAR_DOUBLESTRINGARRAY>(boost::python::object py_value)
+{
+    const long tangoArrayTypeConst = Tango::DEVVAR_DOUBLESTRINGARRAY;
+    typedef TANGO_const2type(tangoArrayTypeConst) TangoArrayType;
+
+    if (!PySequence_Check(py_value.ptr()))
+    {
+        raise_convert2array_DevVarDoubleStringArray();
+    }
+    
+    size_t size = boost::python::len(py_value);
+    if (size != 2)
+    {
+        raise_convert2array_DevVarDoubleStringArray();
+    }
+
+    const boost::python::object
+        &py_dbl = py_value[0],
+        &py_str = py_value[1];
+
+    std::auto_ptr<Tango::DevVarDoubleArray> a_dbl(
+        fast_convert2array<Tango::DEVVAR_DOUBLEARRAY>(py_dbl));
+
+    std::auto_ptr<Tango::DevVarStringArray> a_str(
+        fast_convert2array<Tango::DEVVAR_STRINGARRAY>(py_str));
+
+    std::auto_ptr<TangoArrayType> result(new TangoArrayType());
+
+    result->dvalue = *a_dbl;
+    result->svalue = *a_str;
+
+    return result.release();
+}
+
diff --git a/src/fast_from_py_numpy.hpp b/src/fast_from_py_numpy.hpp
new file mode 100644
index 0000000..a5e3fd3
--- /dev/null
+++ b/src/fast_from_py_numpy.hpp
@@ -0,0 +1,265 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+// This header file is just some template functions moved apart from
+// attribute.cpp, and should only be included there.
+
+#pragma once
+
+#include "tango_numpy.h"
+
+
+#define fast_python_to_tango_buffer_fallback__() \
+    fast_python_to_tango_buffer_sequence<tangoScalarTypeConst>( \
+        py_val, \
+        pdim_x, \
+        pdim_y, \
+        fname, \
+        isImage, \
+        res_dim_x, \
+        res_dim_y \
+    )
+    
+template<long tangoScalarTypeConst>
+inline typename TANGO_const2type(tangoScalarTypeConst)*
+    fast_python_to_tango_buffer_numpy(PyObject* py_val, long* pdim_x, long* pdim_y, const std::string &fname, bool isImage, long& res_dim_x, long& res_dim_y)
+{
+    typedef typename TANGO_const2type(tangoScalarTypeConst) TangoScalarType;
+    typedef typename TANGO_const2arraytype(tangoScalarTypeConst) TangoArrayType;
+    static const int typenum = TANGO_const2numpy(tangoScalarTypeConst);
+    
+    if (!PyArray_Check(py_val)) {
+        return fast_python_to_tango_buffer_fallback__();
+    }
+
+    int nd = PyArray_NDIM(py_val);
+    npy_intp* dims = PyArray_DIMS(py_val);
+    size_t len = 0;
+
+    // Is the array exactly what we need? I mean: The type we need and with
+    // continuous aligned memory?
+    const bool exact_array = (
+                PyArray_CHKFLAGS(py_val, NPY_C_CONTIGUOUS | NPY_ALIGNED)
+            &&  (PyArray_TYPE(py_val) == typenum) );
+
+    if (isImage) {
+        // If dimensions are manually specified (nd must be 1), I don't
+        // know how to handle from numpy
+        if (nd == 1)
+            return fast_python_to_tango_buffer_fallback__();
+        
+        // Check: This is an image!
+        if (nd != 2)
+            Tango::Except::throw_exception(
+                "PyDs_WrongNumpyArrayDimensions",
+                "Expecting a 2 dimensional numpy array (IMAGE attribute).",
+                fname + "()");
+        
+        // If dimensions are manually limited and it's an image, I just
+        // know that if the limit is the real size, then I can safely
+        // ignore it, else let the default path take care...
+        bool dims_ok = true;
+        if (pdim_x)
+            dims_ok = dims_ok && (*pdim_x == dims[1]);
+        if (pdim_y)
+            dims_ok = dims_ok && (*pdim_y == dims[0]);
+        if (!dims_ok)
+            return fast_python_to_tango_buffer_fallback__();
+        
+        len = dims[0]*dims[1];
+        res_dim_x = dims[1];
+        res_dim_y = dims[0];
+    } else {
+        // Check: This is an spectrum!
+        if (nd != 1)
+            Tango::Except::throw_exception(
+                "PyDs_WrongNumpyArrayDimensions",
+                "Expecting a 1 dimensional numpy array (SPECTRUM attribute).",
+                fname + "()");
+        
+        // If x dimension is limited then I only know how to behave
+        // if the array is exact
+        if (pdim_x) {
+            // if x_dim is wrong, instead of throwing an exception I will let
+            // fast_python_to_tgbuffer_sequence throw it:
+            const bool dims_ok = (*pdim_x <= dims[0]);
+            if (!exact_array || !dims_ok)
+                return fast_python_to_tango_buffer_fallback__();
+            len = *pdim_x;
+        } else
+            len = dims[0];
+        res_dim_x = len;
+        res_dim_y = 0;
+    }
+
+    TangoScalarType *tg_data = new TangoScalarType[len];
+
+    void *vd_data = tg_data;
+    
+    if (exact_array) {
+        // The array is exactly what we need, so a plain memcpy is
+        // enough!
+        /// @todo If it is read only we need the copy, but if the
+        /// attribute is read/write, Tango will do the copy himself on
+        /// the calll to set_value(...), so there's no need for us
+        /// to make an extra one...
+        memcpy(vd_data, PyArray_DATA(py_val), len*sizeof(TangoScalarType));
+    } else {
+        // We use numpy to create a copy of the array into the continuous
+        // memory location that we specify.
+        PyObject* py_cont;
+        
+        py_cont = PyArray_SimpleNewFromData(nd, dims, typenum, vd_data);
+        if (!py_cont) {
+            fast_python_to_tango_buffer_deleter__<tangoScalarTypeConst>(tg_data, len);
+            boost::python::throw_error_already_set();
+        }
+        
+        if (PyArray_CopyInto(
+                (PyArrayObject*)py_cont,
+                (PyArrayObject*)py_val) < 0)
+        {
+            Py_DECREF(py_cont);
+            fast_python_to_tango_buffer_deleter__<tangoScalarTypeConst>(tg_data, len);
+            boost::python::throw_error_already_set();
+        }
+        
+        Py_DECREF(py_cont);
+    }
+
+    return tg_data;
+}
+
+template<>
+inline TANGO_const2type(Tango::DEV_STRING)*
+    fast_python_to_tango_buffer_numpy<Tango::DEV_STRING>(PyObject* py_val, long* pdim_x, long* pdim_y, const std::string &fname, bool isImage, long& res_dim_x, long& res_dim_y)
+{
+    static const long tangoScalarTypeConst = Tango::DEV_STRING;
+    return fast_python_to_tango_buffer_fallback__();
+}
+
+template<>
+inline TANGO_const2type(Tango::DEV_ENCODED)*
+    fast_python_to_tango_buffer_numpy<Tango::DEV_ENCODED>(PyObject* py_val, long* pdim_x, long* pdim_y, const std::string &fname, bool isImage, long& res_dim_x, long& res_dim_y)
+{
+    static const long tangoScalarTypeConst = Tango::DEV_ENCODED;
+    return fast_python_to_tango_buffer_fallback__();
+}
+
+#define fast_python_to_corba_buffer_fallback__() \
+    fast_python_to_corba_buffer_sequence<tangoArrayTypeConst>( \
+        py_val, \
+        pdim_x, \
+        fname, \
+        res_dim_x \
+    )
+    
+template<long tangoArrayTypeConst>
+inline typename TANGO_const2scalartype(tangoArrayTypeConst)*
+    fast_python_to_corba_buffer_numpy(PyObject* py_val, long* pdim_x, const std::string &fname, long& res_dim_x)
+{
+    typedef typename TANGO_const2type(tangoArrayTypeConst) TangoArrayType;
+    typedef typename TANGO_const2scalartype(tangoArrayTypeConst) TangoScalarType;
+
+    static const int typenum = TANGO_const2scalarnumpy(tangoArrayTypeConst);
+    
+    if (!PyArray_Check(py_val)) {
+        return fast_python_to_corba_buffer_fallback__();
+    }
+
+    int nd = PyArray_NDIM(py_val);
+    npy_intp* dims = PyArray_DIMS(py_val);
+    size_t len = 0;
+
+    // Is the array exactly what we need? I mean: The type we need and with
+    // continuous aligned memory?
+    const bool exact_array = (
+                PyArray_CHKFLAGS(py_val, NPY_C_CONTIGUOUS | NPY_ALIGNED)
+            &&  (PyArray_TYPE(py_val) == typenum) );
+
+    // Check: This is an spectrum!
+    if (nd != 1)
+        Tango::Except::throw_exception(
+            "PyDs_WrongNumpyArrayDimensions",
+            "Expecting a 1 dimensional numpy array (SPECTRUM attribute).",
+            fname + "()");
+    
+    // If x dimension is limited then I only know how to behave
+    // if the array is exact
+    if (pdim_x) {
+        // if x_dim is wrong, instead of throwing an exception I will let
+        // fast_python_to_tgbuffer_sequence throw it:
+        const bool dims_ok = (*pdim_x <= dims[0]);
+        if (!exact_array || !dims_ok)
+            return fast_python_to_corba_buffer_fallback__();
+        len = *pdim_x;
+    } else
+        len = dims[0];
+    res_dim_x = len;
+
+
+    TangoScalarType *tg_data = TangoArrayType::allocbuf(len);
+
+    void *vd_data = tg_data;
+    
+    if (exact_array) {
+        // The array is exactly what we need, so a plain memcpy is
+        // enough!
+        /// @todo If it is read only we need the copy, but if the
+        /// attribute is read/write, Tango will do the copy himself on
+        /// the calll to set_value(...), so there's no need for us
+        /// to make an extra one...
+        memcpy(vd_data, PyArray_DATA(py_val), len*sizeof(TangoScalarType));
+    } else {
+        // We use numpy to create a copy of the array into the continuous
+        // memory location that we specify.
+        PyObject* py_cont;
+        
+        py_cont = PyArray_SimpleNewFromData(nd, dims, typenum, vd_data);
+        if (!py_cont) {
+            TangoArrayType::freebuf(tg_data);
+            boost::python::throw_error_already_set();
+        }
+        
+        if (PyArray_CopyInto(
+                (PyArrayObject*)py_cont,
+                (PyArrayObject*)py_val) < 0)
+        {
+            Py_DECREF(py_cont);
+            TangoArrayType::freebuf(tg_data);
+            boost::python::throw_error_already_set();
+        }
+        
+        Py_DECREF(py_cont);
+    }
+
+    return tg_data;
+}
+
+template<>
+inline TANGO_const2scalartype(Tango::DEVVAR_STRINGARRAY)*
+    fast_python_to_corba_buffer_numpy<Tango::DEVVAR_STRINGARRAY>(PyObject* py_val, long* pdim_x, const std::string &fname, long& res_dim_x)
+{
+    static const long tangoArrayTypeConst = Tango::DEVVAR_STRINGARRAY;
+    return fast_python_to_corba_buffer_fallback__();
+}
diff --git a/src/from_py.cpp b/src/from_py.cpp
new file mode 100644
index 0000000..e7b8bc4
--- /dev/null
+++ b/src/from_py.cpp
@@ -0,0 +1,316 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include "from_py.h"
+
+using namespace boost::python;
+
+void convert2array(const boost::python::object &py_value, Tango::DevVarCharArray & result)
+{
+    PyObject *py_value_ptr = py_value.ptr();
+    if(PySequence_Check(py_value_ptr) == 0)
+    {
+        raise_(PyExc_TypeError, param_must_be_seq);
+    }
+
+    size_t size = boost::python::len(py_value);
+    result.length(size);
+    if (PyString_Check(py_value_ptr))
+    {
+        char *ch = PyString_AS_STRING(py_value_ptr);
+        for (size_t i=0; i < size; ++i) {
+            result[i] = ch[i];
+        }
+    }
+    else
+    {
+        for (size_t i=0; i < size; ++i) {
+            unsigned char *ch = boost::python::extract<unsigned char *>(py_value[i]);
+            result[i] = ch[0];
+        }
+    }
+}
+
+void convert2array(const object &py_value, StdStringVector & result)
+{
+    PyObject *py_value_ptr = py_value.ptr();
+    if(PySequence_Check(py_value_ptr) == 0)
+    {
+        raise_(PyExc_TypeError, param_must_be_seq);
+    }
+    
+    if (PyString_Check(py_value_ptr))
+    {
+        result.push_back(PyString_AsString(py_value_ptr));
+    }
+    else
+    {
+        size_t size = boost::python::len(py_value);
+        result.reserve(size);
+        
+        for (size_t i=0; i < size; ++i) {
+            char *vi = boost::python::extract<char*>(py_value[i]);
+            result.push_back(vi);
+        }
+    }
+}
+
+void convert2array(const object &py_value, Tango::DevVarStringArray & result)
+{
+    PyObject *py_value_ptr = py_value.ptr();
+    if(PySequence_Check(py_value_ptr) == 0)
+    {
+        raise_(PyExc_TypeError, param_must_be_seq);
+    }
+    
+    if (PyString_Check(py_value_ptr))
+    {
+        result.length(1);
+        result[0] = CORBA::string_dup(PyString_AsString(py_value_ptr));
+    }
+    else
+    {
+        size_t size = boost::python::len(py_value);
+        result.length(size);
+        for (size_t i=0; i < size; ++i) {
+            result[i] = CORBA::string_dup(boost::python::extract<char*>(py_value[i]));
+        }
+    }
+}
+
+void convert2array(const boost::python::object &py_value, Tango::DevVarDoubleStringArray & result)
+{
+    if (!PySequence_Check(py_value.ptr()))
+    {
+        raise_convert2array_DevVarDoubleStringArray();
+    }
+    
+    size_t size = boost::python::len(py_value);
+    if (size != 2)
+    {
+        raise_convert2array_DevVarDoubleStringArray();
+    }
+    
+    const boost::python::object
+        &py_double = py_value[0],
+        &py_str    = py_value[1];
+
+    convert2array(py_double, result.dvalue);
+    convert2array(py_str, result.svalue);
+}
+
+void convert2array(const boost::python::object &py_value, Tango::DevVarLongStringArray & result)
+{
+    if (!PySequence_Check(py_value.ptr()))
+    {
+        raise_convert2array_DevVarLongStringArray();
+    }
+    
+    size_t size = boost::python::len(py_value);
+    if (size != 2)
+    {
+        raise_convert2array_DevVarLongStringArray();
+    }
+    
+    const boost::python::object 
+        py_long = py_value[0],
+        py_str  = py_value[1];
+
+    convert2array(py_long, result.lvalue);
+    convert2array(py_str, result.svalue);
+}
+
+void from_py_object(object &py_obj, Tango::AttributeAlarm &attr_alarm)
+{
+    attr_alarm.min_alarm = extract<const char *>(py_obj.attr("min_alarm"));
+    attr_alarm.max_alarm = extract<const char *>(py_obj.attr("max_alarm"));
+    attr_alarm.min_warning = extract<const char *>(py_obj.attr("min_warning"));
+    attr_alarm.max_warning = extract<const char *>(py_obj.attr("max_warning"));
+    attr_alarm.delta_t = extract<const char *>(py_obj.attr("delta_t"));
+    attr_alarm.delta_val = extract<const char *>(py_obj.attr("delta_val"));
+    convert2array(py_obj.attr("extensions"), attr_alarm.extensions);
+}
+
+void from_py_object(object &py_obj, Tango::ChangeEventProp &change_evt_prop)
+{
+    change_evt_prop.rel_change = extract<const char *>(py_obj.attr("rel_change"));
+    change_evt_prop.abs_change = extract<const char *>(py_obj.attr("abs_change"));
+    convert2array(py_obj.attr("extensions"), change_evt_prop.extensions);
+}
+
+void from_py_object(object &py_obj, Tango::PeriodicEventProp &periodic_evt_prop)
+{
+    periodic_evt_prop.period = extract<const char *>(py_obj.attr("period"));
+    convert2array(py_obj.attr("extensions"), periodic_evt_prop.extensions);
+}
+
+void from_py_object(object &py_obj, Tango::ArchiveEventProp &archive_evt_prop)
+{
+    archive_evt_prop.rel_change = extract<const char *>(py_obj.attr("rel_change"));
+    archive_evt_prop.abs_change = extract<const char *>(py_obj.attr("abs_change"));
+    archive_evt_prop.period = extract<const char *>(py_obj.attr("period"));
+    convert2array(py_obj.attr("extensions"), archive_evt_prop.extensions);
+}
+
+void from_py_object(object &py_obj, Tango::EventProperties &evt_props)
+{
+    object py_ch_event = py_obj.attr("ch_event");
+    object py_per_event = py_obj.attr("per_event");
+    object py_arch_event = py_obj.attr("arch_event");
+        
+    from_py_object(py_ch_event, evt_props.ch_event);
+    from_py_object(py_per_event, evt_props.per_event);
+    from_py_object(py_arch_event, evt_props.arch_event);
+}
+
+
+void from_py_object(object &py_obj, Tango::AttributeConfig &attr_conf)
+{
+    attr_conf.name = extract<const char *>(py_obj.attr("name"));
+    attr_conf.writable = extract<Tango::AttrWriteType>(py_obj.attr("writable"));
+    attr_conf.data_format = extract<Tango::AttrDataFormat>(py_obj.attr("data_format"));
+    attr_conf.data_type = extract<CORBA::Long>(py_obj.attr("data_type"));
+    attr_conf.max_dim_x = extract<CORBA::Long>(py_obj.attr("max_dim_x"));
+    attr_conf.max_dim_y = extract<CORBA::Long>(py_obj.attr("max_dim_y"));
+    attr_conf.description = extract<const char *>(py_obj.attr("description"));
+    attr_conf.label = extract<const char *>(py_obj.attr("label"));
+    attr_conf.unit = extract<const char *>(py_obj.attr("unit"));
+    attr_conf.standard_unit = extract<const char *>(py_obj.attr("standard_unit"));
+    attr_conf.display_unit = extract<const char *>(py_obj.attr("display_unit"));
+    attr_conf.format = extract<const char *>(py_obj.attr("format"));
+    attr_conf.min_value = extract<const char *>(py_obj.attr("min_value"));
+    attr_conf.max_value = extract<const char *>(py_obj.attr("max_value"));
+    attr_conf.min_alarm = extract<const char *>(py_obj.attr("min_alarm"));
+    attr_conf.max_alarm = extract<const char *>(py_obj.attr("max_alarm"));
+    attr_conf.writable_attr_name = extract<const char *>(py_obj.attr("writable_attr_name"));
+    convert2array(py_obj.attr("extensions"), attr_conf.extensions);
+}
+
+void from_py_object(object &py_obj, Tango::AttributeConfig_2 &attr_conf)
+{
+    attr_conf.name = extract<const char *>(py_obj.attr("name"));
+    attr_conf.writable = extract<Tango::AttrWriteType>(py_obj.attr("writable"));
+    attr_conf.data_format = extract<Tango::AttrDataFormat>(py_obj.attr("data_format"));
+    attr_conf.data_type = extract<CORBA::Long>(py_obj.attr("data_type"));
+    attr_conf.max_dim_x = extract<CORBA::Long>(py_obj.attr("max_dim_x"));
+    attr_conf.max_dim_y = extract<CORBA::Long>(py_obj.attr("max_dim_y"));
+    attr_conf.description = extract<const char *>(py_obj.attr("description"));
+    attr_conf.label = extract<const char *>(py_obj.attr("label"));
+    attr_conf.unit = extract<const char *>(py_obj.attr("unit"));
+    attr_conf.standard_unit = extract<const char *>(py_obj.attr("standard_unit"));
+    attr_conf.display_unit = extract<const char *>(py_obj.attr("display_unit"));
+    attr_conf.format = extract<const char *>(py_obj.attr("format"));
+    attr_conf.min_value = extract<const char *>(py_obj.attr("min_value"));
+    attr_conf.max_value = extract<const char *>(py_obj.attr("max_value"));
+    attr_conf.min_alarm = extract<const char *>(py_obj.attr("min_alarm"));
+    attr_conf.max_alarm = extract<const char *>(py_obj.attr("max_alarm"));
+    attr_conf.writable_attr_name = extract<const char *>(py_obj.attr("writable_attr_name"));
+    attr_conf.level = extract<Tango::DispLevel>(py_obj.attr("level"));
+    convert2array(py_obj.attr("extensions"), attr_conf.extensions);
+}
+
+void from_py_object(object &py_obj, Tango::AttributeConfig_3 &attr_conf)
+{
+    attr_conf.name = extract<const char *>(py_obj.attr("name"));
+    attr_conf.writable = extract<Tango::AttrWriteType>(py_obj.attr("writable"));
+    attr_conf.data_format = extract<Tango::AttrDataFormat>(py_obj.attr("data_format"));
+    attr_conf.data_type = extract<CORBA::Long>(py_obj.attr("data_type"));
+    attr_conf.max_dim_x = extract<CORBA::Long>(py_obj.attr("max_dim_x"));
+    attr_conf.max_dim_y = extract<CORBA::Long>(py_obj.attr("max_dim_y"));
+    attr_conf.description = extract<const char *>(py_obj.attr("description"));
+    attr_conf.label = extract<const char *>(py_obj.attr("label"));
+    attr_conf.unit = extract<const char *>(py_obj.attr("unit"));
+    attr_conf.standard_unit = extract<const char *>(py_obj.attr("standard_unit"));
+    attr_conf.display_unit = extract<const char *>(py_obj.attr("display_unit"));
+    attr_conf.format = extract<const char *>(py_obj.attr("format"));
+    attr_conf.min_value = extract<const char *>(py_obj.attr("min_value"));
+    attr_conf.max_value = extract<const char *>(py_obj.attr("max_value"));
+    attr_conf.writable_attr_name = extract<const char *>(py_obj.attr("writable_attr_name"));
+    attr_conf.level = extract<Tango::DispLevel>(py_obj.attr("level"));
+    
+    object py_att_alarm = py_obj.attr("att_alarm");
+    object py_event_prop = py_obj.attr("event_prop");
+        
+    from_py_object(py_att_alarm, attr_conf.att_alarm);
+    from_py_object(py_event_prop, attr_conf.event_prop);
+    convert2array(py_obj.attr("extensions"), attr_conf.extensions);
+    convert2array(py_obj.attr("sys_extensions"), attr_conf.sys_extensions);
+}
+
+
+void from_py_object(object &py_obj, Tango::AttributeConfigList &attr_conf_list)
+{
+    PyObject* py_obj_ptr = py_obj.ptr();
+    
+    if (!PySequence_Check(py_obj_ptr))
+    {
+        attr_conf_list.length(1);
+        from_py_object(py_obj, attr_conf_list[0]);
+        return;
+    }
+    
+    size_t size = boost::python::len(py_obj);
+    attr_conf_list.length(size);
+    for (size_t i=0; i < size; ++i) {
+        object tmp = py_obj[i];
+        from_py_object(tmp, attr_conf_list[i]);
+    }
+}
+
+void from_py_object(object &py_obj, Tango::AttributeConfigList_2 &attr_conf_list)
+{
+    PyObject* py_obj_ptr = py_obj.ptr();
+    
+    if (!PySequence_Check(py_obj_ptr))
+    {
+        attr_conf_list.length(1);
+        from_py_object(py_obj, attr_conf_list[0]);
+        return;
+    }
+    
+    size_t size = boost::python::len(py_obj);
+    attr_conf_list.length(size);
+    for (size_t i=0; i < size; ++i) {
+        object tmp = py_obj[i];
+        from_py_object(tmp, attr_conf_list[i]);
+    }
+}
+
+void from_py_object(object &py_obj, Tango::AttributeConfigList_3 &attr_conf_list)
+{
+    PyObject* py_obj_ptr = py_obj.ptr();
+    
+    if (!PySequence_Check(py_obj_ptr))
+    {
+        attr_conf_list.length(1);
+        from_py_object(py_obj, attr_conf_list[0]);
+        return;
+    }
+    
+    size_t size = boost::python::len(py_obj);
+    attr_conf_list.length(size);
+    for (size_t i=0; i < size; ++i) {
+        object tmp = py_obj[i];
+        from_py_object(tmp, attr_conf_list[i]);
+    }
+}
diff --git a/src/from_py.h b/src/from_py.h
new file mode 100644
index 0000000..3a40e1a
--- /dev/null
+++ b/src/from_py.h
@@ -0,0 +1,259 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#pragma once
+
+#include <boost/python.hpp>
+#include <boost/version.hpp>
+#if BOOST_VERSION < 103400
+#include <boost/python/detail/api_placeholder.hpp>
+#endif
+#include <tango.h>
+
+#include "defs.h"
+#include "tgutils.h"
+#include "pyutils.h"
+#include "tango_numpy.h"
+#include "exception.h"
+
+extern const char *param_must_be_seq;
+
+/**
+ * Converter from python sequence of strings to a std::vector<std::string>
+ *
+ * @param[in] py_value python sequence object or a single string
+ * @param[out] result std string vector to be filled
+ */
+void convert2array(const boost::python::object &py_value, StdStringVector & result);
+
+/**
+ * Converter from python sequence of characters to a Tango::DevVarCharArray
+ *
+ * @param[in] py_value python sequence object or a single string
+ * @param[out] result Tango char array to be filled
+ */
+void convert2array(const boost::python::object &py_value, Tango::DevVarCharArray & result);
+
+/**
+ * Converter from python sequence to a Tango CORBA sequence
+ *
+ * @param[in] py_value python sequence object
+ * @param[out] result CORBA sequence to be filled
+ */
+template<typename TangoElementType>
+void convert2array(const boost::python::object &py_value, _CORBA_Sequence<TangoElementType> & result)
+{
+    size_t size = boost::python::len(py_value);
+    result.length(size);
+    for (size_t i=0; i < size; ++i) {
+        TangoElementType ch = boost::python::extract<TangoElementType>(py_value[i]);
+        result[i] = ch;
+    }
+}
+
+
+/**
+ * Converter from python sequence of strings to a Tango DevVarStringArray
+ *
+ * @param[in] py_value python sequence object or a single string
+ * @param[out] result Tango string array to be filled
+ */
+void convert2array(const boost::python::object &py_value, Tango::DevVarStringArray & result);
+
+inline void raise_convert2array_DevVarDoubleStringArray()
+{
+    Tango::Except::throw_exception(
+        "PyDs_WrongPythonDataTypeForDoubleStringArray",
+        "Converter from python object to DevVarDoubleStringArray needs a python sequence<sequence<double>, sequence<str>>",
+        "convert2array()");
+}
+
+/**
+ * Converter from python sequence<sequence<double>, sequence<str>> to a Tango DevVarDoubleStringArray
+ *
+ * @param[in] py_value python sequence object
+ * @param[out] result Tango array to be filled
+ */
+void convert2array(const boost::python::object &py_value, Tango::DevVarDoubleStringArray & result);
+
+inline void raise_convert2array_DevVarLongStringArray()
+{
+    Tango::Except::throw_exception(
+        "PyDs_WrongPythonDataTypeForLongStringArray",
+        "Converter from python object to DevVarLongStringArray needs a python sequence<sequence<int>, sequence<str>>",
+        "convert2array()");
+}
+
+/**
+ * Converter from python sequence<sequence<int>, sequence<str>> to a Tango DevVarLongStringArray
+ *
+ * @param[in] py_value python sequence object
+ * @param[out] result Tango array to be filled
+ */
+void convert2array(const boost::python::object &py_value, Tango::DevVarLongStringArray & result);
+
+/**
+ * Convert a python sequence into a C++ container
+ * The C++ container must have the push_back method
+ */
+template <typename ContainerType = StdStringVector >
+struct from_sequence
+{
+    static inline void convert(boost::python::object seq, ContainerType& a)
+    {
+        typedef typename ContainerType::value_type T;
+        PyObject *seq_ptr = seq.ptr();
+        Py_ssize_t len = PySequence_Length(seq_ptr);
+        for(Py_ssize_t i = 0; i < len; ++i)
+        {
+            PyObject *o_ptr = PySequence_GetItem(seq_ptr, i);
+            T s = boost::python::extract<T>(o_ptr);
+            a.push_back(s);
+            boost::python::decref(o_ptr);
+        }
+    }
+
+    static inline void convert(boost::python::object seq, Tango::DbData& a)
+    {
+        PyObject *seq_ptr = seq.ptr();
+        Py_ssize_t len = PySequence_Length(seq_ptr);
+        for(Py_ssize_t i = 0; i < len; ++i)
+        {
+            PyObject *o_ptr = PySequence_GetItem(seq_ptr, i);
+            a.push_back(Tango::DbDatum(PyString_AsString(o_ptr)));
+            boost::python::decref(o_ptr);
+        }
+    }
+
+    /**
+     * Convert a python dictionary to a Tango::DbData. The dictionary keys must
+     * be strings representing the DbDatum name. The dictionary value can be
+     * be one of the following:
+     * - Tango::DbDatum : in this case the key is not used, and the
+     *   item inserted in DbData will be a copy of the value
+     * - sequence : it is translated into an array of strings and
+     *   the DbDatum inserted in DbData will have name as the dict key and value
+     *   the sequence of strings
+     * - python object : its string representation is used
+     *   as a DbDatum to be inserted
+     *
+     * @param[in] d the python dictionary to be translated
+     * @param[out] db_data the array of DbDatum to be filled
+     */
+    static inline void convert(boost::python::dict d, Tango::DbData& db_data)
+    {
+        boost::python::object it = d.iteritems();
+        int len = boost::python::extract<int>(d.attr("__len__")()) ;
+        for(int i = 0 ; i < len; ++i)
+        {
+            boost::python::tuple pair = (boost::python::tuple)it.attr("next")();
+            boost::python::object key = pair[0];
+            boost::python::object value = pair[1];
+            PyObject *value_ptr = value.ptr();
+
+            boost::python::extract<Tango::DbDatum> ext(value);
+            if(ext.check())
+            {
+                db_data.push_back(ext());
+                continue;
+            }
+
+            Tango::DbDatum db_datum(PyString_AsString(key.ptr()));
+            if((PySequence_Check(value_ptr)) && (!PyString_Check(value_ptr)))
+            {
+                from_sequence<StdStringVector>::convert(value, db_datum.value_string);
+            }
+            else
+            {
+                boost::python::object value_str = value.attr("__str__")();
+                db_datum.value_string.push_back(PyString_AsString(value_str.ptr()));
+            }
+            db_data.push_back(db_datum);
+        }
+    }
+};
+
+
+extern const char *param_must_be_seq;
+/// This class is useful when you need a sequence like C++ type for
+/// a function argument, and you have exported this type to python.
+/// This will try to convert the parameter directly to the C++ object
+/// (valid if the argument passed was an instance of the exported type).
+/// If it fails, it will use from_sequence::convert to get a copy
+/// of the sequence in the expected format.
+/// So for example we can get a function that accepts an object of
+/// type StdStringVector, or a list of strings, or a tuple of strings...
+template<class SequenceT>
+class CSequenceFromPython
+{
+    SequenceT* m_seq;
+    bool m_own;
+    public:
+    CSequenceFromPython(boost::python::object &py_obj)
+    {
+        boost::python::extract<SequenceT*> ext(py_obj);
+        if (ext.check()) {
+            m_seq = ext();
+            m_own = false;
+        } else {
+            if (PySequence_Check(py_obj.ptr()) == 0)
+                raise_(PyExc_TypeError, param_must_be_seq);
+            if (PyString_Check(py_obj.ptr()) != 0)
+                raise_(PyExc_TypeError, param_must_be_seq);
+
+            m_own = true;
+            //m_seq = new SequenceT(PySequence_Length(Py_obj.ptr()));
+            m_seq = new SequenceT();
+            std::auto_ptr<SequenceT> guard(m_seq);
+            from_sequence<SequenceT>::convert(py_obj, *m_seq);
+            guard.release();
+        }
+    }
+    ~CSequenceFromPython()
+    {
+        if (m_own)
+            delete m_seq;
+    }
+    SequenceT & operator*()
+    {
+        return *m_seq;
+    }
+    const SequenceT & operator*() const
+    {
+        return *m_seq;
+    }
+};
+
+void from_py_object(boost::python::object &, Tango::AttributeAlarm &);
+void from_py_object(boost::python::object &, Tango::ChangeEventProp &);
+void from_py_object(boost::python::object &, Tango::PeriodicEventProp &);
+void from_py_object(boost::python::object &, Tango::ArchiveEventProp &);
+void from_py_object(boost::python::object &, Tango::EventProperties &);
+
+void from_py_object(boost::python::object &, Tango::AttributeConfig &);
+void from_py_object(boost::python::object &, Tango::AttributeConfig_2 &);
+void from_py_object(boost::python::object &, Tango::AttributeConfig_3 &);
+
+void from_py_object(boost::python::object &, Tango::AttributeConfigList &);
+void from_py_object(boost::python::object &, Tango::AttributeConfigList_2 &);
+void from_py_object(boost::python::object &, Tango::AttributeConfigList_3 &);
diff --git a/src/group.cpp b/src/group.cpp
new file mode 100644
index 0000000..fa4438c
--- /dev/null
+++ b/src/group.cpp
@@ -0,0 +1,116 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python/copy_const_reference.hpp>
+#include <boost/python/copy_non_const_reference.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+#include <tango.h>
+#include <memory>
+
+#include "pytgutils.h"
+#include "device_attribute.h"
+
+void export_group_reply_list();
+void export_group_reply();
+void export_group_element();
+
+
+namespace PyGroup
+{
+    using namespace boost::python;
+
+    void add(Tango::Group& self, std::auto_ptr<Tango::Group> grp, int timeout_ms)
+    {
+        Tango::Group* grp_ptr = grp.get();
+        
+        if (grp_ptr) {
+            // After adding grp_ptr into self, self is the responsible of
+            // deleting grp_ptr, so we "nullify" the grp object. It's python
+            // counterpart will still be available, but any method call will
+            // return an exception.
+            self.add(grp_ptr, timeout_ms);
+            grp.release();
+        } else {
+            raise_(PyExc_TypeError,
+                   "Param \"group\" is null. It probably means that it has"
+                    " already been inserted in another group." );
+        }
+    }
+}
+
+void export_group()
+{
+    using namespace boost::python;
+    
+    export_group_reply();
+    export_group_reply_list();
+    export_group_element();
+
+    class_<Tango::Group, bases<Tango::GroupElement>, std::auto_ptr<Tango::Group>, boost::noncopyable > Group(
+        "__Group",
+        init<const std::string&>())
+    ;
+    
+    Group
+        .def("__add",
+            (void (Tango::Group::*) (const std::string &, int))
+            &Tango::Group::add,
+            (arg_("self"), arg_("pattern"), arg_("timeout_ms")=-1) )
+        .def("__add",
+            (void (Tango::Group::*) (const std::vector<std::string> &, int))
+            &Tango::Group::add,
+            (arg_("self"), arg_("patterns"), arg_("timeout_ms")=-1))
+        .def("__add",
+            PyGroup::add,
+            (arg_("self"), arg_("group"), arg_("timeout_ms")=-1) )
+            
+        .def("remove_all", &Tango::Group::remove_all)
+
+        // GroupElement redefinitions of enable/disable. If I didn't
+        // redefine them, the later Group only definitions would
+        // hide the ones defined in GroupElement.
+        .def("enable",
+            &Tango::GroupElement::enable,
+            (arg_("self")) )
+        .def("disable",
+            &Tango::GroupElement::disable,
+            (arg_("self")) )
+        .def("enable",
+            &Tango::Group::enable,
+            (arg_("self"), arg_("dev_name"), arg_("forward")=true) )
+        .def("disable",
+            &Tango::Group::disable,
+            (arg_("self"), arg_("dev_name"), arg_("forward")=true) )
+        
+        .def("get_device_list",
+            &Tango::Group::get_device_list,
+            (arg_("self"), arg_("forward")=true) )
+    ;
+
+    // I am not exporting "find", so all the GroupElemens will be
+    // Groups (there's no way to access a GroupDeviceElement)
+//     class_<Tango::GroupDeviceElement, bases<Tango::GroupElement>, boost::noncopyable > GroupDeviceElement(
+//         "GroupDeviceElement",
+//         no_init)
+//     ;
+}
diff --git a/src/group_element.cpp b/src/group_element.cpp
new file mode 100644
index 0000000..ccf4099
--- /dev/null
+++ b/src/group_element.cpp
@@ -0,0 +1,294 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python/copy_const_reference.hpp>
+#include <boost/python/copy_non_const_reference.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+#include <tango.h>
+
+#include "pytgutils.h"
+#include "device_attribute.h"
+
+namespace PyGroupElement
+{
+    using namespace boost::python;
+
+
+    Tango::GroupCmdReplyList command_inout_reply(Tango::GroupElement &self, long req_id, long timeout_ms)
+    {
+        AutoPythonAllowThreads guard;
+        return self.command_inout_reply(req_id, timeout_ms);
+    }
+
+    static void __update_data_format(Tango::GroupElement &self, Tango::GroupAttrReplyList& r)
+    {
+        // Usually we pass a device_proxy to "convert_to_python" in order to
+        // get the data_format of the DeviceAttribute for Tango versions
+        // older than 7.0. However, GroupAttrReply has no device_proxy to use!
+        // So, we are using update_data_format() in here.
+        // The conver_to_python method is called, without the usual
+        // device_proxy argument, in PyGroupAttrReply::get_data().
+        Tango::GroupAttrReplyList::iterator i, e = r.end();
+        for (i=r.begin(); i != e; ++i) {
+            Tango::DeviceProxy* dev_proxy = self.get_device(i->dev_name());
+            if (!dev_proxy)
+                continue;
+            PyDeviceAttribute::update_data_format( *dev_proxy, &(i->get_data()), 1 );
+        }
+    }
+    
+    Tango::GroupAttrReplyList read_attribute_reply (Tango::GroupElement &self,  long req_id, long timeout_ms = 0 )
+    {
+        Tango::GroupAttrReplyList r;
+        {
+            AutoPythonAllowThreads guard;
+            r = self.read_attribute_reply(req_id, timeout_ms);
+        }
+        __update_data_format(self, r);
+        return r;
+    }
+    
+    Tango::GroupAttrReplyList read_attributes_reply (Tango::GroupElement &self, long req_id, long timeout_ms = 0)
+    {
+        Tango::GroupAttrReplyList r;
+        {
+            AutoPythonAllowThreads guard;
+            r = self.read_attributes_reply(req_id, timeout_ms);
+        }
+        __update_data_format(self, r);
+        return r;
+    }
+
+    long read_attributes_asynch (Tango::GroupElement &self, object py_value, bool forward = true, long reserved = -1)
+    {
+        StdStringVector r;
+        convert2array(py_value, r);
+        return self.read_attributes_asynch(r, forward, reserved);
+    }
+
+    long write_attribute_asynch (Tango::GroupElement &self, const std::string &attr_name, object py_value, bool forward = true, long reserved = -1)
+    {
+        Tango::DeviceAttribute dev_attr;
+        Tango::DeviceProxy* dev_proxy = self.get_device(1);
+        if (dev_proxy)
+            PyDeviceAttribute::reset(dev_attr, attr_name, *dev_proxy, py_value);
+        // If !dev_proxy (no device added in self or his children) then we
+        // don't initialize dev_attr. As a result, the reply will be empty.
+        /// @todo or should we raise an exception instead?
+
+        AutoPythonAllowThreads guard;
+        return self.write_attribute_asynch(dev_attr, forward, reserved);
+    }
+
+    Tango::GroupReplyList write_attribute_reply (Tango::GroupElement &self, long req_id, long timeout_ms = 0)
+    {
+        AutoPythonAllowThreads guard;
+        return self.write_attribute_reply(req_id, timeout_ms);
+    }
+    
+    
+}
+
+
+void export_group_element()
+{
+    using namespace boost::python;
+
+    class_<Tango::GroupElement, std::auto_ptr<Tango::GroupElement>, boost::noncopyable> GroupElement("GroupElement",
+        "The abstract GroupElement class for Group. Not to be initialized\n"
+        "directly.", no_init)
+    ;
+
+    GroupElement
+    //
+    // Group management methods
+    //
+        .def("__add",
+            (void (Tango::GroupElement::*) (const std::string &, int))
+            &Tango::GroupElement::add,
+            (arg_("self"), arg_("pattern"), arg_("timeout_ms")=-1) )
+        .def("__add",
+            (void (Tango::GroupElement::*) (const std::vector<std::string> &, int))
+            &Tango::GroupElement::add,
+            (arg_("self"), arg_("patterns"), arg_("timeout_ms")=-1))
+        .def("__remove",
+            (void (Tango::GroupElement::*) (const std::string &, bool))
+            &Tango::GroupElement::remove,
+            (arg_("self"), arg_("pattern"), arg_("forward")=true))
+        .def("__remove",
+            (void (Tango::GroupElement::*) (const std::vector<std::string> &, bool))
+            &Tango::GroupElement::remove,
+            (arg_("self"), arg_("patterns"), arg_("forward")=true))
+        .def("contains",
+            &Tango::GroupElement::contains,
+            (arg_("self"), arg_("pattern"), arg_("forward")=true) )
+        .def("get_device",
+            (Tango::DeviceProxy* (Tango::GroupElement::*) (const std::string &))
+            &Tango::GroupElement::get_device,
+            (arg_("self"), arg_("dev_name")),
+            return_internal_reference<1>() )
+        .def("get_device",
+            (Tango::DeviceProxy* (Tango::GroupElement::*) (long))
+            &Tango::GroupElement::get_device,
+            (arg_("self"), arg_("idx")),
+            return_internal_reference<1>() )
+        .def("get_group",
+            &Tango::GroupElement::get_group,
+            (arg_("self"), arg_("group_name")),
+            return_internal_reference<1>() )
+
+    //
+    // Tango methods (~ DeviceProxy interface)
+    //
+        .def("ping",
+            pure_virtual(&Tango::GroupElement::ping),
+            (arg_("self"), arg_("forward")=true) )
+        .def("set_timeout_millis",
+            pure_virtual(&Tango::GroupElement::set_timeout_millis),
+            (arg_("self"), arg_("timeout_ms")) )
+        .def("command_inout_asynch",
+            pure_virtual((long (Tango::GroupElement::*) (const std::string&, bool, bool, long))
+            &Tango::GroupElement::command_inout_asynch),
+            (   arg_("self"),
+                arg_("cmd_name"),
+                arg_("forget")=false,
+                arg_("forward")=true,
+                arg_("reserved")=-1) )
+        .def("command_inout_asynch",
+            pure_virtual((long (Tango::GroupElement::*) (const std::string&, const Tango::DeviceData&, bool, bool, long))
+            &Tango::GroupElement::command_inout_asynch),
+            (   arg_("self"),
+                arg_("cmd_name"),
+                arg_("param"),
+                arg_("forget")=false,
+                arg_("forward")=true,
+                arg_("reserved")=-1) )
+        .def("command_inout_reply",
+            PyGroupElement::command_inout_reply,
+            (   arg_("self"),
+                arg_("req_id"),
+                arg_("timeout_ms")=0 ) )
+        .def("read_attribute_asynch",
+            pure_virtual(&Tango::GroupElement::read_attribute_asynch),
+            (   arg_("self"),
+                arg_("attr_name"),
+                arg_("forward")=true,
+                arg_("reserved")=-1) )
+        .def("read_attribute_reply",
+            &PyGroupElement::read_attribute_reply,
+            (   arg_("self"),
+                arg_("req_id"),
+                arg_("timeout_ms")=0 ) )
+        .def("read_attributes_asynch",
+            PyGroupElement::read_attributes_asynch,
+            (   arg_("self"),
+                arg_("attr_names"),
+                arg_("forward")=true,
+                arg_("reserved")=-1) )
+        .def("read_attributes_reply",
+            PyGroupElement::read_attributes_reply,
+            (   arg_("self"),
+                arg_("req_id"),
+                arg_("timeout_ms")=0 ) )
+        .def("write_attribute_asynch",
+            &PyGroupElement::write_attribute_asynch,
+            (   arg_("self"),
+                arg_("attr_name"),
+                arg_("value"),
+                arg_("forward")=true,
+                arg_("reserved")=-1 ) )
+        .def("write_attribute_reply",
+            PyGroupElement::write_attribute_reply,
+            (   arg_("self"),
+                arg_("req_id"),
+                arg_("timeout_ms")=0 ) )
+
+    //
+    // Misc
+    //
+        .def("get_name",
+            &Tango::GroupElement::get_name,
+            (arg_("self")),
+            return_value_policy<copy_const_reference>() )
+        .def("get_fully_qualified_name",
+            &Tango::GroupElement::get_fully_qualified_name,
+            (arg_("self")) )
+        .def("enable",
+            &Tango::GroupElement::enable,
+            (arg_("self")) )
+        .def("disable",
+            &Tango::GroupElement::disable,
+            (arg_("self")) )
+        .def("is_enabled",
+            &Tango::GroupElement::is_enabled,
+            (arg_("self")) )
+        .def("name_equals",
+            &Tango::GroupElement::name_equals,
+            (arg_("self")) )
+        .def("name_matches",
+            &Tango::GroupElement::name_matches,
+            (arg_("self")) )
+        .def("get_size",
+            &Tango::GroupElement::get_size,
+            (arg_("self"), arg_("forward")=true) )
+
+    //
+    // "Should not be used" methods
+    //
+        
+        // According to the header,
+        // The methods are: find, get_parent, set_parent, is_device,
+        // is_group, dump.
+        // I've choosed according to my very personal criteria which are really
+        // needed and which aren't.
+
+        // find looks in both devices and groups, and returns a GroupElement.
+        // Problem is, it is impossible to get DeviceProxy from
+        // GroupDeviceElement (It can be done only by private methods) so
+        // it is useless for us. Our own find can be implemented with
+        // get_device and get_group, and they have different return values
+        // DeviceProxy and Group.
+// 		.def("find",
+// 			&Tango::GroupElement::find,
+// 			(arg_("self"), arg_("pattern?"), arg_("forward")=true ),
+// 			return_internal_reference<1>() )
+
+        // It would return a x.get_group("grp").get_parent() != x
+        // So, as it is not really necessary, we get rid of him...
+//         .def("get_parent",
+//             &Tango::GroupElement::get_parent,
+//             (arg_("self")),
+//             return_internal_reference<1>() )
+
+        // I am not exporting "find", so all the GroupElemens will be
+        // Groups (there's no way to access a GroupDeviceElement)
+//         .def("is_device",
+//             pure_virtual(&Tango::GroupElement::is_device),
+//             (arg_("self")) )
+// 
+//         .def("is_group",
+//             pure_virtual(&Tango::GroupElement::is_group),
+//             (arg_("self")) )
+    ;
+
+}
diff --git a/src/group_reply.cpp b/src/group_reply.cpp
new file mode 100644
index 0000000..ce3765f
--- /dev/null
+++ b/src/group_reply.cpp
@@ -0,0 +1,85 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python/copy_const_reference.hpp>
+#include <boost/python/copy_non_const_reference.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+#include <tango.h>
+
+#include "pytgutils.h"
+#include "device_attribute.h"
+
+namespace PyGroupAttrReply
+{
+    using namespace boost::python;
+    object get_data(Tango::GroupAttrReply& self, PyTango::ExtractAs extract_as)
+    {
+        // Usually we pass a device_proxy to "convert_to_python" in order to
+        // get the data_format of the DeviceAttribute for Tango versions
+        // older than 7.0. However, GroupAttrReply has no device_proxy to use!
+        // So, we are using update_data_format() in:
+        //       GroupElement::read_attribute_reply/read_attributes_reply
+        return PyDeviceAttribute::convert_to_python(
+                new Tango::DeviceAttribute(self.get_data()), extract_as );
+    }
+}
+
+
+void export_group_reply()
+{
+    using namespace boost::python;
+
+    class_<Tango::GroupReply> GroupReply("GroupReply", "", no_init);
+    GroupReply
+//         .def(init<>())
+//         .def(init<const Tango::GroupReply &>())
+//         .def(init<const std::string, const std::string, bool>()) /// @todo args?
+//         .def(init<const std::string, const std::string, const Tango::DevFailed&, bool>())
+        .def("has_failed", &Tango::GroupReply::has_failed)
+        .def("group_element_enabled", &Tango::GroupReply::group_element_enabled)
+        .def("dev_name", &Tango::GroupReply::dev_name, return_value_policy<copy_const_reference>())
+        .def("obj_name", &Tango::GroupReply::obj_name, return_value_policy<copy_const_reference>())
+        .def("get_err_stack", &Tango::GroupReply::get_err_stack, return_value_policy<copy_const_reference>())
+    ;
+
+    
+    class_<Tango::GroupCmdReply, bases<Tango::GroupReply> > GroupCmdReply(
+        "GroupCmdReply",
+        no_init)
+    ;
+    GroupCmdReply
+        .def("get_data_raw", &Tango::GroupCmdReply::get_data, return_internal_reference<1>() )
+    ;
+
+    
+    class_<Tango::GroupAttrReply, bases<Tango::GroupReply> > GroupAttrReply(
+        "GroupAttrReply",
+        no_init)
+    ;
+    GroupAttrReply
+            .def("__get_data",
+                &PyGroupAttrReply::get_data,
+                (   arg_("self"),
+                    arg_("extract_as")=PyTango::ExtractAsNumpy) )
+    ;
+}
diff --git a/src/group_reply_list.cpp b/src/group_reply_list.cpp
new file mode 100644
index 0000000..83ee745
--- /dev/null
+++ b/src/group_reply_list.cpp
@@ -0,0 +1,69 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python/copy_const_reference.hpp>
+#include <boost/python/copy_non_const_reference.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+#include <tango.h>
+
+#include "pytgutils.h"
+#include "device_attribute.h"
+
+void export_group_reply_list()
+{
+    using namespace boost::python;
+
+    typedef std::vector<Tango::GroupReply> StdGroupReplyVector_;
+    typedef std::vector<Tango::GroupCmdReply> StdGroupCmdReplyVector_;
+    typedef std::vector<Tango::GroupAttrReply> StdGroupAttrReplyVector_;
+    
+    class_<Tango::GroupReplyList, bases<StdGroupReplyVector_> > GroupReplyList(
+        "GroupReplyList",
+        init<>())
+    ;
+    GroupReplyList
+        .def("has_failed", &Tango::GroupReplyList::has_failed)
+        .def("reset", &Tango::GroupReplyList::reset)
+        .def("push_back", &Tango::GroupReplyList::push_back)
+    ;
+
+    class_<Tango::GroupCmdReplyList, bases<StdGroupCmdReplyVector_> > GroupCmdReplyList(
+        "GroupCmdReplyList",
+        init<>())
+    ;
+    GroupCmdReplyList
+        .def("has_failed", &Tango::GroupCmdReplyList::has_failed)
+        .def("reset", &Tango::GroupCmdReplyList::reset)
+        .def("push_back", &Tango::GroupCmdReplyList::push_back)
+    ;
+
+    class_<Tango::GroupAttrReplyList, bases<StdGroupAttrReplyVector_> > GroupAttrReplyList(
+        "GroupAttrReplyList",
+        init<>())
+    ;
+    GroupAttrReplyList
+        .def("has_failed", &Tango::GroupAttrReplyList::has_failed)
+        .def("reset", &Tango::GroupAttrReplyList::reset)
+        .def("push_back", &Tango::GroupAttrReplyList::push_back)
+    ;
+}
diff --git a/src/locker_info.cpp b/src/locker_info.cpp
new file mode 100644
index 0000000..7b32ae8
--- /dev/null
+++ b/src/locker_info.cpp
@@ -0,0 +1,56 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+struct PyLockerInfo
+{
+    static inline object get_locker_id(Tango::LockerInfo &li)
+    {
+        return (li.ll == Tango::CPP) ? 
+            object(li.li.LockerPid) :
+            tuple(li.li.UUID);
+    }
+};
+
+void export_locker_info()
+{
+    class_<Tango::LockerInfo>("LockerInfo",
+        "A structure with information about the locker\n"
+        "with the folowing members,\n"
+        " - ll : (PyTango.LockerLanguage) the locker language\n"
+        " - li : (pid_t / UUID) the locker id\n"
+        " - locker_host : (string) the host\n"
+        " - locker_class : (string) the class\n"
+        "\npid_t should be an int, UUID should be a tuple of four numbers.\n"
+        "\nNew in PyTango 7.0.0"
+        )
+        .def_readonly("ll", &Tango::LockerInfo::ll)
+        .add_property("li", &PyLockerInfo::get_locker_id)
+        .def_readonly("locker_host", &Tango::LockerInfo::locker_host)
+        .def_readonly("locker_class", &Tango::LockerInfo::locker_class)
+    ;
+}
diff --git a/src/locking_thread.cpp b/src/locking_thread.cpp
new file mode 100644
index 0000000..de19964
--- /dev/null
+++ b/src/locking_thread.cpp
@@ -0,0 +1,33 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_locking_thread()
+{
+    class_<Tango::LockingThread>("LockingThread")
+    ;
+}
diff --git a/src/periodic_event_info.cpp b/src/periodic_event_info.cpp
new file mode 100644
index 0000000..e1767b5
--- /dev/null
+++ b/src/periodic_event_info.cpp
@@ -0,0 +1,40 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_periodic_event_info()
+{
+    class_<Tango::PeriodicEventInfo>("PeriodicEventInfo",
+        "A structure containing available periodic event information for an attribute\n"
+        "with the folowing members,\n"
+        " - period : string\n"
+        " - extensions : vector of strings\n"
+        )
+        .def_readwrite("period", &Tango::PeriodicEventInfo::period)
+        .def_readwrite("extensions", &Tango::PeriodicEventInfo::extensions)
+    ;
+}
diff --git a/src/poll_device.cpp b/src/poll_device.cpp
new file mode 100644
index 0000000..388f936
--- /dev/null
+++ b/src/poll_device.cpp
@@ -0,0 +1,40 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_poll_device()
+{
+    class_<Tango::PollDevice>("PollDevice",
+        "A structure containing PollDevice information\n"
+        "the following members,\n"
+        " - dev_name : string\n"
+        " - ind_list : sequence<long>\n"
+        "\nNew in PyTango 7.0.0")
+        .def_readwrite("dev_name", &Tango::PollDevice::dev_name)
+        .def_readwrite("ind_list", &Tango::PollDevice::ind_list)
+    ;
+}
diff --git a/src/precompiled_header.hpp b/src/precompiled_header.hpp
new file mode 100644
index 0000000..78ef84d
--- /dev/null
+++ b/src/precompiled_header.hpp
@@ -0,0 +1,32 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#pragma once
+
+// These files are really basic, used everywere within the project
+// but they take a while (seconds!) to process.
+// We don't want to waste those seconds for each cpp file, so we
+// use this precompiled header.
+#include <boost/python.hpp>
+#include <tango.h>
+
diff --git a/src/pytango.cpp b/src/pytango.cpp
new file mode 100644
index 0000000..35210a7
--- /dev/null
+++ b/src/pytango.cpp
@@ -0,0 +1,118 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <boost/version.hpp>
+#if BOOST_VERSION < 103400
+#define DISABLE_BOOST_DOCSTRING_OPTIONS
+#endif
+
+#ifndef DISABLE_PYTANGO_NUMPY
+#   define PY_ARRAY_UNIQUE_SYMBOL pytango_ARRAY_API
+#   include <numpy/arrayobject.h>
+#endif
+
+#include <tango.h>
+#include <iostream>
+#include <string>
+
+using namespace boost::python;
+
+void export_version();
+void export_enums();
+void export_constants();
+void export_base_types();
+void export_event_data();
+void export_attr_conf_event_data();
+void export_data_ready_event_data();
+void export_exceptions();
+void export_api_util();
+void export_connection();
+void export_device_proxy();
+void export_attribute_proxy();
+void export_db();
+void export_callback(); /// @todo not sure were to put it...
+void export_util();
+void export_attr();
+void export_attribute();
+void export_wattribute();
+void export_multi_attribute();
+void export_user_default_attr_prop();
+void export_sub_dev_diag();
+void export_dserver();
+void export_device_class();
+void export_device_impl();
+void export_group();
+void export_log4tango();
+
+BOOST_PYTHON_MODULE(_PyTango)
+{
+
+#ifndef DISABLE_BOOST_DOCSTRING_OPTIONS
+    // Configure generated docstrings
+    const bool show_user_defined = false;
+    const bool show_py_signatures = false;
+
+    docstring_options doc_opts(show_user_defined,
+                               show_py_signatures);
+#endif
+
+    // specify that this module is actually a package
+    boost::python::object package = boost::python::scope();
+    package.attr("__path__") = "PyTango";
+
+    PyEval_InitThreads();
+
+#   ifndef DISABLE_PYTANGO_NUMPY
+        import_array();
+#   endif
+
+    export_callback(); /// @todo not sure were to put it...
+
+    export_version();
+    export_enums();
+    export_constants();
+    export_base_types();
+    export_event_data();
+    export_attr_conf_event_data();
+    export_data_ready_event_data();
+    export_exceptions();
+    export_api_util();
+    export_connection();
+    export_device_proxy();
+    export_attribute_proxy();
+    export_db();
+    export_util();
+    export_attr();
+    export_attribute();
+    export_wattribute();
+    export_multi_attribute();
+    export_user_default_attr_prop();
+    export_sub_dev_diag();
+    export_device_class();
+    export_device_impl();
+    //@warning export_dserver must be made after export_device_impl
+    export_dserver();
+    export_group();
+    export_log4tango();
+}
diff --git a/src/pytgutils.cpp b/src/pytgutils.cpp
new file mode 100644
index 0000000..a9c1c82
--- /dev/null
+++ b/src/pytgutils.cpp
@@ -0,0 +1,31 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+#include "defs.h"
+#include "pytgutils.h"
+
+using namespace boost::python;
+
diff --git a/src/pytgutils.h b/src/pytgutils.h
new file mode 100644
index 0000000..4029f13
--- /dev/null
+++ b/src/pytgutils.h
@@ -0,0 +1,83 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#pragma once
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+#include "defs.h"
+#include "pyutils.h"
+#include "from_py.h"
+#include "to_py.h"
+#include "tgutils.h"
+
+/// Get the python Global Interpret Lock
+class AutoPythonGIL
+{
+    PyGILState_STATE m_gstate;
+    
+    /**
+     * Check python. Before acquiring python GIL check if python as not been
+     * shutdown. If this is the case then the best we can do here is throw an
+     * exception to try to prevent the PyTango from calling python code
+     **/
+    inline void check_python()
+    {
+        if(!Py_IsInitialized())
+        {
+            Tango::Except::throw_exception(
+                "AutoPythonGIL_PythonShutdown",
+                "Trying to execute python code when python interpreter as shutdown.",
+                "AutoPythonGIL::check_python");
+        }
+    }
+
+public:
+    inline AutoPythonGIL(bool safe=true) 
+    { 
+        if (safe) check_python();
+        m_gstate = PyGILState_Ensure(); 
+    }
+    
+    inline ~AutoPythonGIL() { PyGILState_Release(m_gstate); }
+    
+};
+
+/**
+ * Translate a double into a timeval structure
+ *
+ * @param[out] tv timeval structure to be filled with the time
+ * @param[in] t a double representing the time
+ */
+inline void double2timeval(struct timeval &tv, double t)
+{
+    double sec = floor(t);
+#ifdef WIN32
+    tv.tv_usec = (long)((t-sec)*1.0E6);
+    tv.tv_sec = (long)(sec);
+#else
+    tv.tv_usec = (time_t)((t-sec)*1.0E6);
+    tv.tv_sec = (suseconds_t)(sec);
+#endif
+}
diff --git a/src/pyutils.cpp b/src/pyutils.cpp
new file mode 100644
index 0000000..fda94aa
--- /dev/null
+++ b/src/pyutils.cpp
@@ -0,0 +1,66 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+
+#include "defs.h"
+#include "pyutils.h"
+
+using namespace boost::python;
+
+bool is_method_defined(object &obj, const std::string &method_name)
+{
+    return is_method_defined(obj.ptr(), method_name);
+}
+
+bool is_method_defined(PyObject *obj, const std::string &method_name)
+{
+    bool exists, is_method;
+    is_method_defined(obj, method_name, exists, is_method);
+    return exists && is_method;
+}
+
+void is_method_defined(object &obj, const std::string &method_name,
+                       bool &exists, bool &is_method)
+{
+    is_method_defined(obj.ptr(), method_name, exists, is_method);
+}
+
+void is_method_defined(PyObject *obj, const std::string &method_name,
+                       bool &exists, bool &is_method)
+{
+    exists = is_method = false;
+
+    PyObject *meth = PyObject_GetAttrString_(obj, method_name.c_str());
+
+    exists = NULL != meth;
+
+    if (!exists)
+    {
+        PyErr_Clear();
+        return;
+    }
+
+    is_method = (1 == PyCallable_Check(meth));
+    Py_DECREF(meth);
+}
diff --git a/src/pyutils.h b/src/pyutils.h
new file mode 100644
index 0000000..560b8b1
--- /dev/null
+++ b/src/pyutils.h
@@ -0,0 +1,127 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#pragma once
+
+#include <boost/python.hpp>
+
+#define arg_(a) boost::python::arg(a)
+
+#if PY_VERSION_HEX < 0x02050000
+typedef int Py_ssize_t;
+#endif
+
+inline PyObject *PyObject_GetAttrString_(PyObject *o, const std::string &attr_name)
+{
+#if PY_VERSION_HEX < 0x02050000
+    char *attr = const_cast<char *>(attr_name.c_str());
+#else
+    const char *attr = attr_name.c_str();
+#endif
+    return PyObject_GetAttrString(o, attr);
+}
+
+inline PyObject *PyImport_ImportModule_(const std::string &name)
+{
+#if PY_VERSION_HEX < 0x02050000
+    char *attr = const_cast<char *>(name.c_str());
+#else
+    const char *attr = name.c_str();
+#endif
+    return PyImport_ImportModule(attr);
+}
+
+inline void raise_(PyObject *type, const char *message)
+{
+    PyErr_SetString(type, message);
+    boost::python::throw_error_already_set();
+}
+
+/// You should run any I/O intensive operations (like requesting data through
+/// the network) in the context of an object like this.
+class AutoPythonAllowThreads
+{
+    PyThreadState *m_save;
+    
+public:
+    
+    inline void giveup() { if (m_save) { PyEval_RestoreThread(m_save); m_save = 0; } }
+    
+    inline AutoPythonAllowThreads() { m_save = PyEval_SaveThread(); } ;
+    inline ~AutoPythonAllowThreads() {giveup();} ;
+};
+
+/**
+ * Determines if the given method name exists and is callable
+ * within the python class
+ *
+ * @param[in] obj object to search for the method
+ * @param[in] method_name the name of the method
+ *
+ * @return returns true is the method exists or false otherwise
+ */
+bool is_method_defined(boost::python::object &obj, const std::string &method_name);
+
+/**
+ * Determines if the given method name exists and is callable
+ * within the python class
+ *
+ * @param[in] obj object to search for the method
+ * @param[in] method_name the name of the method
+ *
+ * @return returns true is the method exists or false otherwise
+ */
+bool is_method_defined(PyObject *obj, const std::string &method_name);
+
+/**
+ * Determines if the given method name exists and is callable
+ * within the python class
+ *
+ * @param[in] obj object to search for the method
+ * @param[in] method_name the name of the method
+ * @param[out] exists set to true if the symbol exists or false otherwise
+ * @param[out] is_method set to true if the symbol exists and is a method
+ *             or false otherwise
+ */
+void is_method_defined(PyObject *obj, const std::string &method_name,
+                       bool &exists, bool &is_method);
+
+/**
+ * Determines if the given method name exists and is callable
+ * within the python class
+ *
+ * @param[in] obj object to search for the method
+ * @param[in] method_name the name of the method
+ * @param[out] exists set to true if the symbol exists or false otherwise
+ * @param[out] is_method set to true if the symbol exists and is a method
+ *             or false otherwise
+ */
+void is_method_defined(boost::python::object &obj, const std::string &method_name,
+                       bool &exists, bool &is_method);
+
+#define PYTANGO_MOD \
+    boost::python::object pytango((boost::python::handle<>(boost::python::borrowed(PyImport_AddModule("PyTango")))));
+    
+#define CALL_METHOD(retType, self, name, ...) \
+    boost::python::call_method<retType>(self, name , __VA_ARGS__);
+    
diff --git a/src/server/attr.cpp b/src/server/attr.cpp
new file mode 100644
index 0000000..c3fbc4c
--- /dev/null
+++ b/src/server/attr.cpp
@@ -0,0 +1,143 @@
+#include <boost/python.hpp>
+#include <tango.h>
+
+#include "server/attr.h"
+
+using namespace boost::python;
+
+void PyAttr::set_user_prop(vector<Tango::AttrProperty> &user_prop,
+                           Tango::UserDefaultAttrProp &def_prop)
+{
+
+//
+// Is there any user defined prop. defined ?
+//
+
+    long nb_prop = user_prop.size();
+    if (nb_prop == 0)
+        return;
+
+    for (long loop = 0;loop < nb_prop;loop++)
+    {
+        Tango::AttrProperty  prop = user_prop[loop];
+        string &prop_name = prop.get_name();
+        const char *prop_value = prop.get_value().c_str();
+
+        if (prop_name == "label")
+            def_prop.set_label(prop_value);
+        else if (prop_name == "description")
+            def_prop.set_description(prop_value);
+        else if (prop_name == "unit")
+            def_prop.set_unit(prop_value);
+        else if (prop_name == "standard_unit")
+            def_prop.set_standard_unit(prop_value);
+        else if (prop_name == "display_unit")
+            def_prop.set_display_unit(prop_value);
+        else if (prop_name == "format")
+            def_prop.set_format(prop_value);
+        else if (prop_name == "min_value")
+            def_prop.set_min_value(prop_value);
+        else if (prop_name == "max_value")
+            def_prop.set_max_value(prop_value);
+        else if (prop_name == "min_alarm")
+            def_prop.set_min_alarm(prop_value);
+        else if (prop_name == "max_alarm")
+            def_prop.set_max_alarm(prop_value);
+        else if (prop_name == "min_warning")
+            def_prop.set_min_warning(prop_value);
+        else if (prop_name == "max_warning")
+            def_prop.set_max_warning(prop_value);
+        else if (prop_name == "delta_val")
+            def_prop.set_delta_val(prop_value);
+        else if (prop_name == "delta_t")
+            def_prop.set_delta_t(prop_value);
+        else if (prop_name == "abs_change")
+            def_prop.set_abs_change(prop_value);
+        else if (prop_name == "rel_change")
+            def_prop.set_rel_change(prop_value);
+        else if (prop_name == "period")
+            def_prop.set_period(prop_value);
+        else if (prop_name == "archive_abs_change")
+            def_prop.set_archive_abs_change(prop_value);
+        else if (prop_name == "archive_rel_change")
+            def_prop.set_archive_rel_change(prop_value);
+        else if (prop_name == "archive_period")
+            def_prop.set_archive_period(prop_value);
+    }
+}
+
+void export_attr()
+{
+    class_<Tango::Attr, boost::noncopyable>("Attr",
+        init<const char *, long, optional<Tango::AttrWriteType, const char *> >())
+
+        .def("set_default_properties", &Tango::Attr::set_default_properties)
+        .def("set_disp_level", &Tango::Attr::set_disp_level)
+        .def("set_polling_period", &Tango::Attr::set_polling_period)
+        .def("set_memorized", &Tango::Attr::set_memorized)
+        .def("set_memorized_init", &Tango::Attr::set_memorized_init)
+        .def("set_change_event", &Tango::Attr::set_change_event)
+        .def("is_change_event", &Tango::Attr::is_change_event)
+        .def("is_check_change_criteria", &Tango::Attr::is_check_change_criteria)
+        .def("set_archive_event", &Tango::Attr::set_archive_event)
+        .def("is_archive_event", &Tango::Attr::is_archive_event)
+        .def("is_check_archive_criteria", &Tango::Attr::is_check_archive_criteria)
+        .def("get_name", &Tango::Attr::get_name,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_format", &Tango::Attr::get_format)
+        .def("get_writable", &Tango::Attr::get_writable)
+        .def("get_type", &Tango::Attr::get_type)
+        .def("get_disp_level", &Tango::Attr::get_disp_level)
+        .def("get_polling_period", &Tango::Attr::get_polling_period)
+        .def("get_memorized", &Tango::Attr::get_memorized)
+        .def("get_memorized_init", &Tango::Attr::get_memorized_init)
+        .def("get_assoc", &Tango::Attr::get_assoc,
+            return_value_policy<copy_non_const_reference>())
+        .def("is_assoc", &Tango::Attr::is_assoc)
+        .def("get_class_properties", &Tango::Attr::get_class_properties,
+            return_internal_reference<>())
+        .def("get_user_default_properties", &Tango::Attr::get_user_default_properties,
+            return_internal_reference<>())
+        .def("set_class_properties", &Tango::Attr::set_class_properties)
+        .def("check_type", &Tango::Attr::check_type)
+        .def("read", &Tango::Attr::read)
+        .def("write", &Tango::Attr::write)
+        .def("is_allowed", &Tango::Attr::is_allowed)
+    ;
+
+    class_<Tango::SpectrumAttr, bases<Tango::Attr>, boost::noncopyable>("SpectrumAttr",
+        init<const char *, long, Tango::AttrWriteType, long>())
+    ;
+
+    class_<Tango::ImageAttr, bases<Tango::SpectrumAttr>, boost::noncopyable>("ImageAttr",
+        init<const char *, long, Tango::AttrWriteType, long, long>())
+    ;
+
+//    class_<PyAttr>("PyAttr", no_init)
+//        .def("set_allowed", &PyAttr::set_allowed)
+//        .def("set_read_name", &PyAttr::set_read_name)
+//        .def("set_write_name", &PyAttr::set_write_name)
+//    ;
+//
+//    class_<PyScaAttr, bases<Tango::Attr, PyAttr>, boost::noncopyable>("PyScaAttr",
+//        init<const std::string &, long , Tango::AttrWriteType>())
+//    ;
+//
+//    class_<PySpecAttr, bases<Tango::SpectrumAttr, PyAttr>, boost::noncopyable>("PySpecAttr",
+//        init<const std::string &, long , Tango::AttrWriteType, long>())
+//    ;
+//
+//    class_<PyImaAttr, bases<Tango::ImageAttr, PyAttr>, boost::noncopyable>("PyImaAttr",
+//        init<const std::string &, long , Tango::AttrWriteType, long, long>())
+//    ;
+
+    class_<Tango::AttrProperty>("AttrProperty",
+        init<const char *, const char *>())
+        .def(init<const char *, long>())
+        .def("get_value", &Tango::AttrProperty::get_value,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_lg_value", &Tango::AttrProperty::get_lg_value)
+        .def("get_name", &Tango::AttrProperty::get_name,
+            return_value_policy<copy_non_const_reference>())
+    ;
+}
diff --git a/src/server/attr.h b/src/server/attr.h
new file mode 100644
index 0000000..5a430aa
--- /dev/null
+++ b/src/server/attr.h
@@ -0,0 +1,429 @@
+#ifndef _ATTR_H_
+#define _ATTR_H_
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+#include "exception.h"
+#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:
+    /**
+     * Constructor
+     */
+    PyAttr()
+    {}
+
+    /**
+     * Desctructor
+     */
+    virtual ~PyAttr()
+    {}
+
+    /**
+     * Read one attribute. This method forward the action to the python method.
+     *
+     * @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";
+            Tango::Except::throw_exception("PyTango_ReadAttributeMethodNotFound",
+                o.str(), "PyTango::Attr::read");
+        }
+        
+        CALL_ATTR_METHOD_VARGS(dev, read_name.c_str(), boost::ref(att))
+    }
+
+    /**
+     * Write one attribute. This method forward the action to the python method.
+     *
+     * @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";
+            Tango::Except::throw_exception("PyTango_WriteAttributeMethodNotFound",
+                o.str(), "PyTango::Attr::write");
+        }
+        CALL_ATTR_METHOD_VARGS(dev, write_name.c_str(), boost::ref(att))
+    }
+
+    /**
+     * Decide if it is allowed to read/write the attribute
+     *
+     * @param[in] dev The device on which the attribute has to be read/written
+     * @param[in] ty The requets type (read or write)
+     *
+     * @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;
+    }
+
+    /**
+     * Sets the is_allowed method name for this attribute
+     *
+     * @param[in] name the is_allowed method name
+     */
+    inline void set_allowed_name(const std::string &name)
+    {
+        py_allowed_name = name;
+    }
+
+    /**
+     * Sets the read method name for this attribute
+     *
+     * @param[in] name the read method name
+     */
+    inline void set_read_name(const std::string &name)
+    {
+        read_name = name;
+    }
+
+    /**
+     * Sets the write method name for this attribute
+     *
+     * @param[in] name the write method name
+     */
+    inline void set_write_name(const std::string &name)
+    {
+        write_name = name;
+    }
+
+    /**
+     * Transfer user property from a vector of AttrProperty
+     * to a UserDefaultAttrProp
+     *
+     * @param[in] user_prop the AttrProperty vector
+     * @param[out] def_prop  the UserDefaultAttrProp instance
+     */
+    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);
+    }
+    
+private:
+
+    /** the name of the is allowed python method */
+    std::string py_allowed_name;
+    
+    /** the name of the read attribute python method */
+    std::string read_name;
+
+    /** the name of the write attribute python method */
+    std::string write_name;
+};
+
+/**
+ * The python class representing a scalar attribute
+ */
+class PyScaAttr: public Tango::Attr,
+                 public PyAttr
+{
+public:
+
+    /**
+     * Python Scalar Attribute constructor
+     *
+     * @param[in] na The attribute name
+     * @param[in] type  The attribute data type
+     * @param[in] w The attribute writable type
+     */
+    PyScaAttr(const std::string &na, long type, Tango::AttrWriteType w)
+        : Tango::Attr(na.c_str(), type, w)
+    {}
+
+    /**
+     * Python Scalar Attribute constructor
+     *
+     * @param[in] na The attribute name
+     * @param[in] type  The attribute data type
+     * @param[in] w The attribute writable type
+     * @param[in] ww The attribute max dim x
+     * @param[in] user_prop The attribute user default properties
+     */
+    PyScaAttr(const std::string &na, long type, Tango::AttrWriteType w,
+               std::vector<Tango::AttrProperty> &user_prop)
+        : Tango::Attr(na.c_str(), type, w)
+    {
+        if (user_prop.size() == 0)
+            return;
+
+        Tango::UserDefaultAttrProp def_prop;
+        set_user_prop(user_prop,def_prop);
+        set_default_properties(def_prop);
+    }
+
+    /**
+     * Python Scalar Attribute destructor
+     */
+    ~PyScaAttr() {};
+
+    /**
+     * Decide if it is allowed to read/write the attribute
+     *
+     * @param[in] dev The device on which the attribute has to be read/written
+     * @param[in] ty The requets type (read or write)
+     *
+     * @return a boolean set to true if it is allowed to execute
+     *         the command. Otherwise, returns false
+     */
+    inline virtual bool is_allowed(Tango::DeviceImpl *dev, Tango::AttReqType ty)
+    {
+        return PyAttr::is_allowed(dev, ty);
+    }
+
+    /**
+     * Read one attribute. This method forward the action to the python method.
+     *
+     * @param[in] dev The device on which the attribute has to be read
+     * @param[in, out] att the attribute
+     */
+    inline virtual void read(Tango::DeviceImpl *dev, Tango::Attribute &att)
+    {
+        return PyAttr::read(dev, att);
+    }
+
+    /**
+     * Write one attribute. This method forward the action to the python method.
+     *
+     * @param[in] dev The device on which the attribute has to be written
+     * @param[in, out] att the attribute
+     */
+    virtual void write(Tango::DeviceImpl *dev, Tango::WAttribute &att)
+    {
+        return PyAttr::write(dev, att);
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+
+
+class PySpecAttr: public Tango::SpectrumAttr,
+                  public PyAttr
+{
+public:
+    /**
+     * Python Spectrum Attribute constructor
+     *
+     * @param[in] na The attribute name
+     * @param[in] type  The attribute data type
+     * @param[in] w The attribute writable type
+     * @param[in] xx The attribute max dim x
+     */
+    PySpecAttr(const std::string &na, long type, Tango::AttrWriteType w, long xx)
+        : Tango::SpectrumAttr(na.c_str(), type, w, xx)
+    {}
+
+    /**
+     * Python Spectrum Attribute constructor
+     *
+     * @param[in] na The attribute name
+     * @param[in] type  The attribute data type
+     * @param[in] w The attribute writable type
+     * @param[in] xx The attribute max dim x
+     * @param[in] user_prop The attribute user default properties
+     */
+    PySpecAttr(const std::string &na, long type, Tango::AttrWriteType w, long xx,
+               std::vector<Tango::AttrProperty> &user_prop)
+        : Tango::SpectrumAttr(na.c_str(), type, w, xx)
+    {
+        if (user_prop.size() == 0)
+            return;
+
+        Tango::UserDefaultAttrProp def_prop;
+        set_user_prop(user_prop,def_prop);
+        set_default_properties(def_prop);
+    }
+
+    /**
+     * Python Spectrum Attribute destructor
+     */
+    ~PySpecAttr()
+    {}
+
+    /**
+     * Decide if it is allowed to read/write the attribute
+     *
+     * @param[in] dev The device on which the attribute has to be read/written
+     * @param[in] ty The requets type (read or write)
+     *
+     * @return a boolean set to true if it is allowed to execute
+     *         the command. Otherwise, returns false
+     */
+    inline virtual bool is_allowed(Tango::DeviceImpl *dev, Tango::AttReqType ty)
+    {
+        return PyAttr::is_allowed(dev, ty);
+    }
+
+    /**
+     * Read one attribute. This method forward the action to the python method.
+     *
+     * @param[in] dev The device on which the attribute has to be read
+     * @param[in, out] att the attribute
+     */
+    inline virtual void read(Tango::DeviceImpl *dev, Tango::Attribute &att)
+    {
+        return PyAttr::read(dev, att);
+    }
+
+    /**
+     * Write one attribute. This method forward the action to the python method.
+     *
+     * @param[in] dev The device on which the attribute has to be written
+     * @param[in, out] att the attribute
+     */
+    virtual void write(Tango::DeviceImpl *dev, Tango::WAttribute &att)
+    {
+        return PyAttr::write(dev, att);
+    }
+};
+
+//------------------------------------------------------------------------------------------------
+
+class PyImaAttr: public Tango::ImageAttr,
+                 public PyAttr
+{
+public:
+    /**
+     * Python Image Attribute constructor
+     *
+     * @param[in] na The attribute name
+     * @param[in] type  The attribute data type
+     * @param[in] w The attribute writable type
+     * @param[in] xx The attribute max dim x
+     * @param[in] yy The attribute max dim y
+     */
+    PyImaAttr(const std::string &na, long type, Tango::AttrWriteType w, long xx, long yy)
+        : Tango::ImageAttr(na.c_str(), type, w, xx, yy)
+    {}
+
+    /**
+     * Python Image Attribute constructor
+     *
+     * @param[in] na The attribute name
+     * @param[in] type  The attribute data type
+     * @param[in] w The attribute writable type
+     * @param[in] xx The attribute max dim x
+     * @param[in] yy The attribute max dim y
+     * @param[in] user_prop The attribute user default properties
+     */
+    PyImaAttr(const std::string &na, long type, Tango::AttrWriteType w, long xx, long yy,
+               std::vector<Tango::AttrProperty> &user_prop)
+        : Tango::ImageAttr(na.c_str(), type, w, xx, yy)
+    {
+        if (user_prop.size() == 0)
+            return;
+
+        Tango::UserDefaultAttrProp def_prop;
+        set_user_prop(user_prop,def_prop);
+        set_default_properties(def_prop);
+    }
+
+    /**
+     * Python Image Attribute destructor
+     */
+    ~PyImaAttr()
+    {}
+
+    /**
+     * Decide if it is allowed to read/write the attribute
+     *
+     * @param[in] dev The device on which the attribute has to be read/written
+     * @param[in] ty The requets type (read or write)
+     *
+     * @return a boolean set to true if it is allowed to execute
+     *         the command. Otherwise, returns false
+     */
+    inline virtual bool is_allowed(Tango::DeviceImpl *dev, Tango::AttReqType ty)
+    {
+        return PyAttr::is_allowed(dev, ty);
+    }
+
+    /**
+     * Read one attribute. This method forward the action to the python method.
+     *
+     * @param[in] dev The device on which the attribute has to be read
+     * @param[in, out] att the attribute
+     */
+    inline virtual void read(Tango::DeviceImpl *dev, Tango::Attribute &att)
+    {
+        return PyAttr::read(dev, att);
+    }
+
+    /**
+     * Write one attribute. This method forward the action to the python method.
+     *
+     * @param[in] dev The device on which the attribute has to be written
+     * @param[in, out] att the attribute
+     */
+    virtual void write(Tango::DeviceImpl *dev, Tango::WAttribute &att)
+    {
+        return PyAttr::write(dev, att);
+    }
+};
+
+#endif
diff --git a/src/server/attribute.cpp b/src/server/attribute.cpp
new file mode 100644
index 0000000..e15ea7c
--- /dev/null
+++ b/src/server/attribute.cpp
@@ -0,0 +1,461 @@
+#include <boost/python.hpp>
+#include <boost/python/return_value_policy.hpp>
+#include <string>
+#include <tango.h>
+
+#include "defs.h"
+#include "pytgutils.h"
+#include "attribute.h"
+#include "fast_from_py.h"
+
+using namespace boost::python;
+
+# ifdef WIN32
+#   define PYTG_TIME_FROM_DOUBLE(dbl, tv) \
+            if (true) { \
+                tv.time = (time_t)floor(dbl); \
+                tv.millitm = (unsigned short)((dbl - tv.time)*1.0e3); \
+            } else (void)0
+#   define PYTG_NEW_TIME_FROM_DOUBLE(dbl, tv) \
+            struct _timeb tv; PYTG_TIME_FROM_DOUBLE(dbl, tv)
+# else
+#   define PYTG_TIME_FROM_DOUBLE(dbl, tv) double2timeval(tv, dbl);
+#   define PYTG_NEW_TIME_FROM_DOUBLE(dbl, tv) \
+            struct timeval tv; PYTG_TIME_FROM_DOUBLE(dbl, tv)
+#endif
+
+
+inline static void throw_wrong_python_data_type(const std::string &att_name,
+                                         const char *method)
+{
+    TangoSys_OMemStream o;
+    o << "Wrong Python type for attribute " << att_name << ends;
+    Tango::Except::throw_exception(
+            (const char *)"PyDs_WrongPythonDataTypeForAttribute",
+            o.str(), method);
+}
+
+inline static void throw_wrong_python_data_type_in_array(const std::string &att_name,
+                                                  long idx,
+                                                  const char *method)
+{
+    TangoSys_OMemStream o;
+    o << "Wrong Python type for attribute " << att_name
+      << ".\nElement with index " << idx << " in sequence does not "
+      << "have a correct type." << ends;
+
+    Tango::Except::throw_exception(
+            (const char *)"PyDs_WrongPythonDataTypeForAttribute",
+            o.str(), method);
+}
+
+namespace PyAttribute
+{
+    /**
+     * Tango Attribute set_value wrapper for scalar attributes
+     *
+     * @param att attribute reference
+     * @param value new attribute value
+     */
+    template<long tangoTypeConst>
+    inline void __set_value_scalar(Tango::Attribute &att,
+                                   boost::python::object &value)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+
+        /*
+           I hate doing this because tango inside is doing a new again when
+           set_value_date_quality is invoked with the release flag to true
+           the other option would be to use per thread tango data like it was 
+           done in v3.0.4
+           I prefer this one since it decouples TangoC++ from PyTango and creating
+           a scalar is not so expensive after all
+        */
+        std::auto_ptr<TangoScalarType> cpp_val(new TangoScalarType);
+        
+        from_py<tangoTypeConst>::convert(value, *cpp_val);
+        att.set_value(cpp_val.release(), 1, 0, true);
+    }
+
+    /**
+     * ATTENTION: this template specialization is done to close a memory leak
+     *            that exists up to tango 7.1.1 for string read_write attributes
+     *
+     * Tango Attribute set_value wrapper for scalar string attributes
+     * 
+     * @param att attribute reference
+     * @param value new attribute value
+     */
+    /*
+    template<>
+    inline void __set_value_scalar<Tango::DEV_STRING>(Tango::Attribute &att,
+                                                      boost::python::object &value)
+    {
+        Tango::DevString *v = new Tango::DevString;
+
+        if (att.get_writable() == Tango::READ)
+        { // No memory leak here. Do the standard thing
+            from_py<Tango::DEV_STRING>::convert(value, *v);
+        }
+        else
+        { // MEMORY LEAK: use the python string directly instead of creating a
+          // string
+            v[0] = PyString_AsString(value.ptr());
+        }
+        att.set_value(v, 1, 0, true);
+    }
+    */
+    
+    /**
+     * Tango Attribute set_value wrapper for DevEncoded attributes
+     *
+     * @param att attribute reference
+     * @param data_str new attribute data string
+     * @param data new attribute data
+     */
+    inline void __set_value(Tango::Attribute &att,
+                            boost::python::str &data_str,
+                            boost::python::str &data)
+    {
+        extract<Tango::DevString> val_str(data_str.ptr());
+        if (!val_str.check())
+        {
+            throw_wrong_python_data_type(att.get_name(), "set_value()");
+        }
+        extract<Tango::DevString> val(data.ptr());
+        if (!val.check())
+        {
+            throw_wrong_python_data_type(att.get_name(), "set_value()");
+        }
+
+        Tango::DevString val_str_real = val_str;
+        Tango::DevString val_real = val;
+        att.set_value(&val_str_real, (Tango::DevUChar*)val_real, (long)len(data));
+    }
+
+
+    /**
+     * Tango Attribute set_value_date_quality wrapper for scalar attributes
+     *
+     * @param att attribute reference
+     * @param value new attribute value
+     * @param t timestamp
+     * @param quality attribute quality
+     */
+    template<long tangoTypeConst>
+    inline void __set_value_date_quality_scalar(Tango::Attribute &att,
+                                                boost::python::object &value,
+                                                double t, Tango::AttrQuality quality)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+
+        PYTG_NEW_TIME_FROM_DOUBLE(t, tv);
+        
+        /*
+           I hate doing because tango inside is doing a new again when
+           set_value_date_quality is invoked with the release flag to true
+           the other option would be to use per thread tango data like it was 
+           done in v3.0.4
+           I prefer this one since it decouples TangoC++ from PyTango and creating
+           a scalar is not so expensive after all
+        */
+        std::auto_ptr<TangoScalarType> cpp_val(new TangoScalarType);
+        
+        from_py<tangoTypeConst>::convert(value, *cpp_val);
+        att.set_value_date_quality(cpp_val.release(), tv, quality, 1, 0, true);
+    }
+
+
+    /**
+     * ATTENTION: this template specialization is done to close a memory leak
+     *            that exists up to tango 7.1.1 for string read_write attributes
+     *
+     * Tango Attribute set_value_date_quality wrapper for scalar string attributes
+     * 
+     * @param att attribute reference
+     * @param value new attribute value
+     * @param t timestamp
+     * @param quality attribute quality
+     */
+    /*
+    template<>
+    inline void __set_value_date_quality_scalar<Tango::DEV_STRING>(Tango::Attribute &att,
+                                                boost::python::object &value,
+                                                double t, Tango::AttrQuality quality)
+    {
+        PYTG_NEW_TIME_FROM_DOUBLE(t, tv);
+        
+        Tango::DevString *v = new Tango::DevString;
+        if (att.get_writable() == Tango::READ)
+        { // No memory leak here. Do the standard thing
+            from_py<Tango::DEV_STRING>::convert(value, *v);
+        }
+        else
+        { // MEMORY LEAK: use the python string directly instead of creating a string
+            v[0] = PyString_AsString(value.ptr());
+        }
+        att.set_value_date_quality(v, tv, quality, 1, 0, true);
+    }
+    */
+
+    /**
+     * Tango Attribute set_value_date_quality wrapper for DevEncoded attributes
+     *
+     * @param att attribute reference
+     * @param data_str new attribute data string
+     * @param data new attribute data
+     * @param t timestamp
+     * @param quality attribute quality
+     */
+    inline void __set_value_date_quality(Tango::Attribute &att,
+                                         boost::python::str &data_str,
+                                         boost::python::str &data,
+                                         double t, Tango::AttrQuality quality)
+    {
+        extract<Tango::DevString> val_str(data_str.ptr());
+        if (!val_str.check())
+        {
+            throw_wrong_python_data_type(att.get_name(), "set_value()");
+        }
+        extract<Tango::DevUChar*> val(data.ptr());
+        if (!val.check())
+        {
+            throw_wrong_python_data_type(att.get_name(), "set_value()");
+        }
+
+        PYTG_NEW_TIME_FROM_DOUBLE(t, tv);
+        Tango::DevString val_str_real = val_str;
+        Tango::DevUChar *val_real = val;
+        att.set_value_date_quality(&val_str_real, val_real, (long)len(data), tv, quality);
+    }
+
+    template<long tangoTypeConst>
+    void __set_value_date_quality_array(
+            Tango::Attribute& att,
+            boost::python::object &value,
+            double time,
+            Tango::AttrQuality* quality,
+            long* x,
+            long* y,
+            const std::string &fname,
+            bool isImage)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+        typedef typename TANGO_const2arraytype(tangoTypeConst) TangoArrayType;
+
+        if (!PySequence_Check(value.ptr()))
+        {
+            // avoid bug in tango 7.0 to 7.1.1: DevEncoded is not defined in CmdArgTypeName
+            const char *arg_type = tangoTypeConst == Tango::DEV_ENCODED ? 
+                "DevEncoded" : 
+                Tango::CmdArgTypeName[tangoTypeConst];
+                
+            TangoSys_OMemStream o;
+            o << "Wrong Python type for attribute " << att.get_name()
+                << "of type " << arg_type << ". Expected a sequence." << ends;
+
+            Tango::Except::throw_exception(
+                    "PyDs_WrongPythonDataTypeForAttribute",
+                    o.str(),
+                    fname + "()");
+        }
+
+        TangoScalarType* data_buffer;
+
+        long res_dim_x=0, res_dim_y=0;
+        data_buffer = fast_python_to_tango_buffer<tangoTypeConst>(
+                 value.ptr(), x, y, fname, isImage, res_dim_x, res_dim_y);
+
+        static const bool release = true;
+
+        if (quality) {
+            PYTG_NEW_TIME_FROM_DOUBLE(time, tv);
+            att.set_value_date_quality(
+                data_buffer, tv, *quality, res_dim_x, res_dim_y, release);
+        } else {
+            att.set_value(data_buffer, res_dim_x, res_dim_y, release);
+        }
+    }
+
+
+
+    inline void __set_value(const std::string & fname, Tango::Attribute &att, boost::python::object &value, long* x, long *y, double t = 0.0, Tango::AttrQuality* quality = 0)
+    {
+        long type = att.get_data_type();
+        Tango::AttrDataFormat format = att.get_data_format();
+
+        const bool isScalar = (format == Tango::SCALAR);
+        const bool isImage = (format == Tango::IMAGE);
+
+        if (isScalar) {
+            if ((x && ((*x) > 1)) || (y && (*y) > 0)) {
+                TangoSys_OMemStream o;
+                o << "Cannot call " << fname;
+                if (y)
+                    o << "(data, dim_x, dim_y) on scalar attribute ";
+                else
+                    o << "(data, dim_x) on scalar attribute ";
+
+                if (quality)
+                    o << att.get_name() << ". Use set_value_date_quality(data) instead" << ends;
+                else
+                    o << att.get_name() << ". Use set_value(data) instead" << ends;
+
+                Tango::Except::throw_exception(
+                        "PyDs_WrongPythonDataTypeForAttribute",
+                        o.str(),
+                        fname + "()");
+            } else {
+                if (quality)
+                    TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(type, __set_value_date_quality_scalar, att, value, t, *quality);
+                else
+                    TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(type, __set_value_scalar, att, value);
+            }
+        } else {
+            TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(type,
+                __set_value_date_quality_array,
+                    att, value, t, quality, x, y, fname, isImage);
+        }
+    }
+
+    inline void __set_value(const std::string & fname, Tango::Attribute &att, boost::python::str &data_str, boost::python::str &data, double t = 0.0, Tango::AttrQuality* quality = 0)
+    {
+        if (quality)
+            __set_value_date_quality(att, data_str, data, t, *quality);
+        else
+            __set_value(att, data_str, data);
+    }
+
+    inline void set_value(Tango::Attribute &att, boost::python::object &value)
+    { __set_value("set_value", att, value, 0, 0); }
+
+    inline void set_value(Tango::Attribute &att, boost::python::str &data_str, boost::python::str &data)
+    { __set_value("set_value", att, data_str, data); }
+
+    inline void set_value(Tango::Attribute &att, boost::python::object &value, long x)
+    { __set_value("set_value", att, value, &x, 0); }
+
+    inline void set_value(Tango::Attribute &att, boost::python::object &value, long x, long y)
+    { __set_value("set_value", att, value, &x, &y); }
+
+    inline void set_value_date_quality(Tango::Attribute &att,
+                                       boost::python::object &value, double t,
+                                       Tango::AttrQuality quality)
+    { __set_value("set_value_date_quality", att, value, 0, 0, t, &quality); }
+
+    inline void set_value_date_quality(Tango::Attribute &att,
+                                       boost::python::str &data_str,
+                                       boost::python::str &data,
+                                       double t,
+                                       Tango::AttrQuality quality)
+    { __set_value("set_value_date_quality", att, data_str, data, t, &quality); }
+
+    inline void set_value_date_quality(Tango::Attribute &att,
+                                       boost::python::object &value,
+                                       double t, Tango::AttrQuality quality,
+                                       long x)
+    { __set_value("set_value_date_quality", att, value, &x, 0, t, &quality); }
+
+    inline void set_value_date_quality(Tango::Attribute &att,
+                                       boost::python::object &value,
+                                       double t, Tango::AttrQuality quality,
+                                       long x, long y)
+    { __set_value("set_value_date_quality", att, value, &x, &y, t, &quality); }
+};
+
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(set_quality_overloads,
+                                       Tango::Attribute::set_quality, 1, 2);
+
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(set_change_event_overloads,
+                                       Tango::Attribute::set_change_event, 1, 2);
+
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(set_archive_event_overloads,
+                                       Tango::Attribute::set_archive_event, 1, 2);
+
+void export_attribute()
+{
+    enum_<Tango::Attribute::alarm_flags>("alarm_flags")
+        .value("min_level", Tango::Attribute::min_level)
+        .value("max_level", Tango::Attribute::max_level)
+        .value("rds", Tango::Attribute::rds)
+        .value("min_warn", Tango::Attribute::min_warn)
+        .value("max_warn", Tango::Attribute::max_warn)
+        .value("numFlags", Tango::Attribute::numFlags)
+    ;
+
+    class_<Tango::Attribute>("Attribute", no_init)
+        .def("is_write_associated", &Tango::Attribute::is_writ_associated)
+        .def("is_min_alarm", &Tango::Attribute::is_min_alarm)
+        .def("is_max_alarm", &Tango::Attribute::is_max_alarm)
+        .def("is_min_warning", &Tango::Attribute::is_min_warning)
+        .def("is_max_warning", &Tango::Attribute::is_max_warning)
+        .def("is_rds_alarm", &Tango::Attribute::is_rds_alarm)
+        //TODO .def("is_alarmed", &Tango::Attribute::is_alarmed)
+        .def("is_polled", &Tango::Attribute::is_polled)
+        .def("check_alarm", &Tango::Attribute::check_alarm)
+        .def("get_writable", &Tango::Attribute::get_writable)
+        .def("get_name", &Tango::Attribute::get_name,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_data_type", &Tango::Attribute::get_data_type)
+        .def("get_data_format", &Tango::Attribute::get_data_format)
+        .def("get_assoc_name", &Tango::Attribute::get_assoc_name, 
+            return_value_policy<copy_non_const_reference>())
+        .def("get_assoc_ind", &Tango::Attribute::get_assoc_ind)
+        .def("set_assoc_ind", &Tango::Attribute::set_assoc_ind)
+        .def("get_date", &Tango::Attribute::get_date, 
+            return_internal_reference<>())
+        .def("set_date",
+             (void (Tango::Attribute::*) (Tango::TimeVal &))
+             &Tango::Attribute::set_date)
+        .def("get_label", &Tango::Attribute::get_label, 
+            return_value_policy<copy_non_const_reference>())
+        .def("get_quality", &Tango::Attribute::get_quality, 
+            return_value_policy<copy_non_const_reference>())
+        .def("set_quality", &Tango::Attribute::set_quality, 
+            set_quality_overloads())
+        .def("get_data_size", &Tango::Attribute::get_data_size)
+        .def("get_x", &Tango::Attribute::get_x)
+        .def("get_max_dim_x", &Tango::Attribute::get_max_dim_x)
+        .def("get_y", &Tango::Attribute::get_y)
+        .def("get_max_dim_y", &Tango::Attribute::get_max_dim_y)
+        .def("get_polling_period", &Tango::Attribute::get_polling_period)
+        .def("set_attr_serial_model", &Tango::Attribute::set_attr_serial_model)
+        .def("get_attr_serial_model", &Tango::Attribute::get_attr_serial_model)
+        
+        .def("set_value",
+            (void (*) (Tango::Attribute &, boost::python::object &))
+            &PyAttribute::set_value)
+        .def("set_value",
+            (void (*) (Tango::Attribute &, boost::python::str &, boost::python::str &))
+            &PyAttribute::set_value)
+        .def("set_value",
+            (void (*) (Tango::Attribute &, boost::python::object &, long))
+            &PyAttribute::set_value)
+        .def("set_value",
+            (void (*) (Tango::Attribute &, boost::python::object &, long, long))
+            &PyAttribute::set_value)
+        .def("set_value_date_quality",
+            (void (*) (Tango::Attribute &, boost::python::object &, double t, Tango::AttrQuality quality))
+            &PyAttribute::set_value_date_quality)
+        .def("set_value_date_quality",
+            (void (*) (Tango::Attribute &, boost::python::str &, boost::python::str &, double t, Tango::AttrQuality quality))
+            &PyAttribute::set_value_date_quality)
+        .def("set_value_date_quality",
+            (void (*) (Tango::Attribute &, boost::python::object &, double t, Tango::AttrQuality quality, long))
+            &PyAttribute::set_value_date_quality)
+        .def("set_value_date_quality",
+            (void (*) (Tango::Attribute &, boost::python::object &, double t, Tango::AttrQuality quality, long, long))
+            &PyAttribute::set_value_date_quality)
+        
+        .def("set_change_event", &Tango::Attribute::set_change_event, 
+            set_change_event_overloads())
+        .def("set_archive_event", &Tango::Attribute::set_archive_event, 
+            set_archive_event_overloads())
+            
+        .def("is_change_event", &Tango::Attribute::is_change_event)
+        .def("is_check_change_criteria", &Tango::Attribute::is_check_change_criteria)
+        .def("is_archive_event", &Tango::Attribute::is_archive_event)
+        .def("is_check_archive_criteria", &Tango::Attribute::is_check_archive_criteria)
+        .def("remove_configuration", &Tango::Attribute::remove_configuration)
+    ;
+}
diff --git a/src/server/attribute.h b/src/server/attribute.h
new file mode 100644
index 0000000..299702f
--- /dev/null
+++ b/src/server/attribute.h
@@ -0,0 +1,33 @@
+#ifndef _ATTRIBUTE_H_
+#define _ATTRIBUTE_H_
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+namespace PyAttribute
+{
+    void set_value(Tango::Attribute &, boost::python::object &);
+
+    void set_value(Tango::Attribute &, boost::python::str &,
+                   boost::python::str &);
+
+    void set_value(Tango::Attribute &, boost::python::object &, long);
+
+    void set_value(Tango::Attribute &, boost::python::object &, long, long);
+
+    void set_value_date_quality(Tango::Attribute &, boost::python::object &,
+                                double, Tango::AttrQuality);
+
+    void set_value_date_quality(Tango::Attribute &, boost::python::str &,
+                                boost::python::str &, double,
+                                Tango::AttrQuality);
+
+    void set_value_date_quality(Tango::Attribute &, boost::python::object &,
+                                double, Tango::AttrQuality , long);
+
+    void set_value_date_quality(Tango::Attribute &, boost::python::object &,
+                                double, Tango::AttrQuality , long, long);
+};
+
+
+#endif // _ATTRIBUTE_H_
diff --git a/src/server/command.cpp b/src/server/command.cpp
new file mode 100644
index 0000000..ffdfe9a
--- /dev/null
+++ b/src/server/command.cpp
@@ -0,0 +1,248 @@
+#include <boost/python.hpp>
+#include <boost/python/return_value_policy.hpp>
+#include <tango.h>
+
+#include "exception.h"
+#include "pytgutils.h"
+#include "fast_from_py.h"
+#include "server/device_impl.h"
+#include "server/command.h"
+
+#ifndef DISABLE_PYTANGO_NUMPY
+#   include "to_py_numpy.hpp"
+#endif
+
+#include <memory>
+
+using namespace boost::python;
+
+//+-------------------------------------------------------------------------
+//
+// method : 		PyCmd::is_allowed
+//
+// description : 	Decide if it is allowed to execute the command
+//
+// argin : - dev : The device on which the command has to be excuted
+//	   - any : The input data
+//
+// This method returns a boolean set to True if it is allowed to execute
+// the command. Otherwise, returns false
+//
+//--------------------------------------------------------------------------
+bool PyCmd::is_allowed(Tango::DeviceImpl *dev, const CORBA::Any &any)
+{
+    if (py_allowed_defined == true)
+    {
+        PyDeviceImplBase *dev_ptr = dynamic_cast<PyDeviceImplBase *>(dev);
+        //Device_4ImplWrap *dev_ptr = static_cast<Device_4ImplWrap *>(dev);
+
+        AutoPythonGIL __py_lock;
+
+        bool returned_value = true;
+        try
+        {
+            returned_value = call_method<bool>(dev_ptr->the_self, py_allowed_name.c_str());
+        }
+        catch(error_already_set &eas)
+        {
+            handle_python_exception(eas);
+        }
+
+        return returned_value;
+    }
+    else
+        return true;
+}
+
+
+void allocate_any(CORBA::Any *&any_ptr)
+{
+    try
+    {
+        any_ptr = new CORBA::Any();
+    }
+    catch (bad_alloc)
+    {
+        Tango::Except::throw_exception(
+            "API_MemoryAllocation",
+            "Can't allocate memory in server",
+            "PyCmd::allocate_any()");
+    }
+}
+
+void throw_bad_type(const char *type)
+{
+    TangoSys_OMemStream o;
+
+    o << "Incompatible command argument type, expected type is : Tango::" 
+      << type << ends;
+    Tango::Except::throw_exception(
+            "API_IncompatibleCmdArgumentType",
+            o.str(),
+            "PyCmd::extract()");
+}
+
+template<long tangoTypeConst>
+void insert_scalar(boost::python::object &o, CORBA::Any &any)
+{
+    typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+    
+    any <<= extract<TangoScalarType>(o);
+}
+
+template<>
+void insert_scalar<Tango::DEV_VOID>(boost::python::object &o, CORBA::Any &any)
+{}
+
+template<>
+void insert_scalar<Tango::DEV_BOOLEAN>(boost::python::object &o, CORBA::Any &any)
+{
+    Tango::DevBoolean value = extract<Tango::DevBoolean>(o);
+    CORBA::Any::from_boolean any_value(value);
+
+    any <<= any_value;
+}
+
+template<long tangoArrayTypeConst>
+void insert_array(boost::python::object &o, CORBA::Any &any)
+{   
+    typedef typename TANGO_const2type(tangoArrayTypeConst) TangoArrayType;
+
+    // Destruction will be handled by CORBA, not by Tango.
+    TangoArrayType* data = fast_convert2array<tangoArrayTypeConst>(o);
+    
+    // By giving a pointer to <<= we are giving ownership of the data 
+    // buffer to CORBA
+    any <<= data;
+}
+
+template<long tangoTypeConst>
+void extract_scalar(const CORBA::Any &any, boost::python::object &o)
+{
+    typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+    
+    TangoScalarType data;
+    
+    if ((any >>= data) == false)
+        throw_bad_type(Tango::CmdArgTypeName[tangoTypeConst]);
+
+    o = object(data);
+}
+
+template<>
+void extract_scalar<Tango::DEV_STRING>(const CORBA::Any &any, boost::python::object &o)
+{
+    Tango::ConstDevString data;
+    
+    if ((any >>= data) == false)
+        throw_bad_type(Tango::CmdArgTypeName[Tango::DEV_STRING]);
+
+    o = object(data);
+}
+
+template<>
+void extract_scalar<Tango::DEV_VOID>(const CORBA::Any &any, boost::python::object &o)
+{}
+
+/// This callback is run to delete Tango::DevVarXArray* objects.
+/// It is called by python. The array was associated with an attribute
+/// value object that is not being used anymore.
+/// @param ptr_ The array object.
+/// @param type_ The type of the array objects. We need it to convert ptr_
+///              to the proper type before deleting it.
+///              ex: Tango::DEVVAR_SHORTARRAY.
+static void dev_var_x_array_deleter__(void * ptr_, void *type_)
+{
+    long type = reinterpret_cast<long>(type_);
+
+    TANGO_DO_ON_ATTRIBUTE_DATA_TYPE(type,
+        delete static_cast<TANGO_const2type(tangoTypeConst)*>(ptr_);
+    );
+}
+
+template<long tangoArrayTypeConst>
+void extract_array(const CORBA::Any &any, boost::python::object &py_result)
+{
+    typedef typename TANGO_const2type(tangoArrayTypeConst) TangoArrayType;
+    
+    TangoArrayType *tmp_ptr;
+
+    if ((any >>= tmp_ptr) == false)
+        throw_bad_type(Tango::CmdArgTypeName[tangoArrayTypeConst]);
+
+#   ifndef DISABLE_PYTANGO_NUMPY
+      // For numpy we need a 'guard' object that handles the memory used
+      // by the numpy object (releases it).
+      // But I cannot manage memory inside our 'any' object, because it is
+      // const and handles it's memory itself. So I need a copy before
+      // creating the object.
+      TangoArrayType* copy_ptr = new TangoArrayType(*tmp_ptr);
+
+      // numpy.ndarray() does not own it's memory, so we need to manage it.
+      // We can assign a 'base' object that will be informed (decref'd) when
+      // the last copy of numpy.ndarray() disappears.
+      // PyCObject is intended for that kind of things. It's seen as a
+      // black box object from python. We assign him a function to be called
+      // when it is deleted -> the function deletes de data.
+      PyObject* guard = PyCObject_FromVoidPtrAndDesc(
+              static_cast<void*>(copy_ptr),
+              reinterpret_cast<void*>(tangoArrayTypeConst),
+              dev_var_x_array_deleter__);
+      if (!guard ) {
+          delete copy_ptr;
+          throw_error_already_set();
+      }
+
+      py_result = to_py_numpy<tangoArrayTypeConst>(copy_ptr, object(handle<>(guard)));
+#   else
+      py_result = to_py_list(tmp_ptr);
+#   endif
+}
+
+CORBA::Any *PyCmd::execute(Tango::DeviceImpl *dev, const CORBA::Any &param_any)
+{
+    PyDeviceImplBase *dev_ptr = dynamic_cast<PyDeviceImplBase *>(dev);
+    
+    AutoPythonGIL python_guard;
+    try 
+    {   
+        // This call extracts the CORBA any into a python object.
+        // So, the result is that param_py = param_any.
+        // It is done with some template magic.
+        boost::python::object param_py;
+        TANGO_DO_ON_DEVICE_DATA_TYPE(in_type, 
+            extract_scalar<tangoTypeConst>(param_any, param_py);
+        , 
+            extract_array<tangoTypeConst>(param_any, param_py);
+        );
+
+        // Execute the python call for the command
+        object ret_py_obj;
+
+        if (in_type == Tango::DEV_VOID)
+        {
+            ret_py_obj = call_method<object>(dev_ptr->the_self, name.c_str());
+        }
+        else
+        {
+            ret_py_obj = call_method<object>(dev_ptr->the_self, name.c_str(), param_py);
+        }
+        
+        CORBA::Any *ret_any;
+        allocate_any(ret_any);
+        std::auto_ptr<CORBA::Any> ret_any_guard(ret_any);
+
+        // It does: ret_any = ret_py_obj
+        TANGO_DO_ON_DEVICE_DATA_TYPE(out_type, 
+            insert_scalar<tangoTypeConst>(ret_py_obj, *ret_any);
+        ,
+            insert_array<tangoTypeConst>(ret_py_obj, *ret_any);
+        );
+        
+        return ret_any_guard.release();
+    } catch(error_already_set &eas) {
+        handle_python_exception(eas);
+        return 0; // Should not happen, handle_python_exception rethrows in
+                  // a Tango friendly manner
+    }
+}
diff --git a/src/server/command.h b/src/server/command.h
new file mode 100644
index 0000000..f82f62c
--- /dev/null
+++ b/src/server/command.h
@@ -0,0 +1,33 @@
+#ifndef _COMMAND_H_
+#define _COMMAND_H_
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+class PyCmd : public Tango::Command
+{
+public:
+    PyCmd(string &name, Tango::CmdArgType in, Tango::CmdArgType out,
+          string &in_desc, string &out_desc, Tango::DispLevel  level)
+    :Tango::Command(name,in,out,in_desc,out_desc, level),py_allowed_defined(false)	{};
+
+    PyCmd(const char *name, Tango::CmdArgType in, Tango::CmdArgType out)
+    :Tango::Command(name,in,out),py_allowed_defined(false)	{};
+
+    PyCmd(const char *name, Tango::CmdArgType in, Tango::CmdArgType out,
+          const char *in_desc, const char *out_desc, Tango::DispLevel  level)
+    :Tango::Command(name,in,out,in_desc,out_desc, level),py_allowed_defined(false)	{};
+
+    virtual ~PyCmd() {};
+
+    virtual CORBA::Any *execute (Tango::DeviceImpl *dev, const CORBA::Any &any);
+    virtual bool is_allowed (Tango::DeviceImpl *dev, const CORBA::Any &any);
+
+    void set_allowed(const string &name) {py_allowed_defined=true;py_allowed_name=name;}
+
+private:
+    bool py_allowed_defined;
+    string	py_allowed_name;
+};
+
+#endif
diff --git a/src/server/device_class.cpp b/src/server/device_class.cpp
new file mode 100644
index 0000000..85345c6
--- /dev/null
+++ b/src/server/device_class.cpp
@@ -0,0 +1,289 @@
+#include "pytgutils.h"
+#include "exception.h"
+#include "server/device_class.h"
+#include "server/attr.h"
+#include "server/command.h"
+
+#include <sstream>
+
+using namespace boost::python;
+
+#define __AUX_DECL_CALL_DEVCLASS_METHOD \
+    AutoPythonGIL __py_lock;
+
+#define __AUX_CATCH_PY_EXCEPTION \
+    catch(boost::python::error_already_set &eas) \
+    { handle_python_exception(eas); }
+
+#define CALL_DEVCLASS_METHOD(name) \
+    __AUX_DECL_CALL_DEVCLASS_METHOD \
+    try { boost::python::call_method<void>(m_self, #name); } \
+    __AUX_CATCH_PY_EXCEPTION
+
+#define CALL_DEVCLASS_METHOD_VARGS(name, ...) \
+    __AUX_DECL_CALL_DEVCLASS_METHOD \
+    try { boost::python::call_method<void>(m_self, #name, __VA_ARGS__); } \
+    __AUX_CATCH_PY_EXCEPTION
+
+void CppDeviceClass::create_command(const std::string &cmd_name,
+                                    Tango::CmdArgType param_type,
+                                    Tango::CmdArgType result_type,
+                                    const std::string &param_desc,
+                                    const std::string &result_desc,
+                                    Tango::DispLevel display_level,
+                                    bool default_command,
+                                    long polling_period,
+                                    const std::string &is_allowed)
+{
+    PyCmd *cmd_ptr = new PyCmd(cmd_name.c_str(), param_type, result_type,
+                               param_desc.c_str(), result_desc.c_str(),
+                               display_level);
+
+    if (!is_allowed.empty())
+    {
+        cmd_ptr->set_allowed(is_allowed);
+    }
+
+    if (polling_period > 0)
+        cmd_ptr->set_polling_period(polling_period);
+    if (default_command)
+        set_default_command(cmd_ptr);
+    else
+        command_list.push_back(cmd_ptr);
+}
+
+void CppDeviceClass::create_attribute(vector<Tango::Attr *> &att_list,
+                                    const std::string &attr_name,
+                                    Tango::CmdArgType attr_type,
+                                    Tango::AttrDataFormat attr_format,
+                                    Tango::AttrWriteType attr_write,
+                                    long dim_x, long dim_y,
+                                    Tango::DispLevel display_level,
+                                    long polling_period,
+                                    bool memorized, bool hw_memorized,
+                                    const std::string &read_method_name,
+                                    const std::string &write_method_name,
+                                    const std::string &is_allowed_name,
+                                    Tango::UserDefaultAttrProp &att_prop)
+{
+    //
+    // Create the attribute objet according to attribute format
+    //
+
+    PyScaAttr *sca_attr_ptr = NULL;
+    PySpecAttr *spec_attr_ptr = NULL;
+    PyImaAttr *ima_attr_ptr= NULL;
+    PyAttr *py_attr_ptr = NULL;
+    Tango::Attr *attr_ptr = NULL;
+
+    switch (attr_format)
+    {
+        case Tango::SCALAR:
+            sca_attr_ptr = new PyScaAttr(attr_name, attr_type, attr_write);
+            py_attr_ptr = sca_attr_ptr;
+            attr_ptr = sca_attr_ptr;
+            break;
+
+        case Tango::SPECTRUM:
+            spec_attr_ptr = new PySpecAttr(attr_name.c_str(), attr_type, attr_write, dim_x);
+            py_attr_ptr = spec_attr_ptr;
+            attr_ptr = spec_attr_ptr;
+            break;
+
+        case Tango::IMAGE:
+            ima_attr_ptr = new PyImaAttr(attr_name.c_str(), attr_type, attr_write, dim_x, dim_y);
+            py_attr_ptr = ima_attr_ptr;
+            attr_ptr = ima_attr_ptr;
+            break;
+
+        default:
+            TangoSys_OMemStream o;
+            o << "Attribute " << attr_name << " has an unexpected data format\n"
+              << "Please report this bug to the PyTango development team"
+              << ends;
+            Tango::Except::throw_exception(
+                    (const char *)"PyDs_UnexpectedAttributeFormat",
+                    o.str(),
+                    (const char *)"create_attribute");
+            break;
+    }
+
+    py_attr_ptr->set_read_name(read_method_name);
+    py_attr_ptr->set_write_name(write_method_name);
+    py_attr_ptr->set_allowed_name(is_allowed_name);
+
+    attr_ptr->set_default_properties(att_prop);
+    attr_ptr->set_disp_level(display_level);
+    if (memorized)
+    {
+        attr_ptr->set_memorized();
+        attr_ptr->set_memorized_init(hw_memorized);
+    }
+
+    if (polling_period > 0)
+        attr_ptr->set_polling_period(polling_period);
+
+    att_list.push_back(attr_ptr);
+}
+
+void CppDeviceClassWrap::init_class()
+{
+    AutoPythonGIL python_guard;
+    
+    //@TODO remove this line when Tango C++ is cleaned up
+    set_py_class(true);
+
+    signal_handler_defined = is_method_defined(m_self, "signal_handler");
+}
+
+void CppDeviceClassWrap::attribute_factory(std::vector<Tango::Attr *> &att_list)
+{
+    //
+    // make sure we pass the same vector object to the python method
+    //
+    object py_att_list(
+                handle<>(
+                    to_python_indirect<
+                        std::vector<Tango::Attr *>,
+                        detail::make_reference_holder>()(att_list)));
+    CALL_DEVCLASS_METHOD_VARGS(_DeviceClass__attribute_factory, py_att_list)
+}
+
+void CppDeviceClassWrap::command_factory()
+{
+    CALL_DEVCLASS_METHOD(_DeviceClass__command_factory)
+}
+
+void CppDeviceClassWrap::device_factory(const Tango::DevVarStringArray *dev_list)
+{
+    CALL_DEVCLASS_METHOD_VARGS(device_factory, dev_list)
+}
+
+void CppDeviceClassWrap::signal_handler(long signo)
+{
+    if (signal_handler_defined == true)
+    {
+        CALL_DEVCLASS_METHOD_VARGS(signal_handler, signo)
+    }
+    else
+    {
+        Tango::DeviceClass::signal_handler(signo);
+    }
+}
+
+void CppDeviceClassWrap::default_signal_handler(long signo)
+{
+    this->Tango::DeviceClass::signal_handler(signo);
+}
+
+void CppDeviceClassWrap::delete_class()
+{
+    AutoPythonGIL __py_lock;
+
+    try
+    {
+        //
+        // Call the delete_class_list function in order to clear the global
+        // constructed class Python list. It is MANDATORY to destroy these objects
+        // from Python. Otherwise, there are "seg fault" when Python exit.
+        // It tooks me quite a long time to find this...
+        //
+        PYTANGO_MOD
+        pytango.attr("delete_class_list")();
+    }
+    catch(error_already_set &eas)
+    {
+        handle_python_exception(eas);
+    }
+
+}
+
+namespace PyDeviceClass
+{
+
+    object get_device_list(CppDeviceClass &self)
+    {
+        boost::python::list py_dev_list;
+        vector<Tango::DeviceImpl *> dev_list = self.get_device_list();
+        for(vector<Tango::DeviceImpl *>::iterator it = dev_list.begin(); it != dev_list.end(); ++it)
+        {
+            object py_value = object(
+                        handle<>(
+                            to_python_indirect<
+                                Tango::DeviceImpl*,
+                                detail::make_reference_holder>()(*it)));
+            py_dev_list.append(py_value);
+        }
+        return py_dev_list;
+    }
+}
+
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS (export_device_overload,
+                                        CppDeviceClass::export_device, 1, 2)
+
+#if ((defined sun) || (defined WIN32))
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS (register_signal_overload,
+                                        Tango::DeviceClass::register_signal, 1, 1)
+#else
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS (register_signal_overload,
+                                        Tango::DeviceClass::register_signal, 1, 2)
+#endif
+
+void export_device_class()
+{
+    void (Tango::DeviceClass::*add_wiz_dev_prop_)(string &,string &) =
+        &Tango::DeviceClass::add_wiz_dev_prop;
+    void (Tango::DeviceClass::*add_wiz_dev_prop__)(string &,string &,string &) =
+        &Tango::DeviceClass::add_wiz_dev_prop;
+    void (Tango::DeviceClass::*add_wiz_class_prop_)(string &,string &) =
+        &Tango::DeviceClass::add_wiz_class_prop;
+    void (Tango::DeviceClass::*add_wiz_class_prop__)(string &,string &,string &) =
+        &Tango::DeviceClass::add_wiz_class_prop;
+
+    class_<CppDeviceClass, CppDeviceClassWrap, boost::noncopyable>("_DeviceClass",
+        init<const std::string &>())
+
+        .def("device_factory", &CppDeviceClassWrap::device_factory)
+        .def("export_device", &CppDeviceClass::export_device,
+            export_device_overload())
+        .def("cpp_add_device", &CppDeviceClass::add_device)
+        .def("register_signal",&Tango::DeviceClass::register_signal,
+            register_signal_overload())
+        .def("unregister_signal", &Tango::DeviceClass::unregister_signal)
+        .def("signal_handler", &Tango::DeviceClass::signal_handler,
+            &CppDeviceClassWrap::default_signal_handler)
+        .def("get_name", &Tango::DeviceClass::get_name,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_type", &Tango::DeviceClass::get_type,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_doc_url", &Tango::DeviceClass::get_doc_url,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_cvs_tag", &Tango::DeviceClass::get_cvs_tag,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_cvs_location",&Tango::DeviceClass::get_cvs_location,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_device_list",&PyDeviceClass::get_device_list)
+        .def("set_type",
+            (void (Tango::DeviceClass::*) (const char *))
+            &Tango::DeviceClass::set_type)
+        .def("add_wiz_dev_prop",
+            (void (Tango::DeviceClass::*) (const std::string &, const std::string &))
+            add_wiz_dev_prop_)
+        .def("add_wiz_dev_prop",
+            (void (Tango::DeviceClass::*) (const std::string &, const std::string &, const std::string &))
+            add_wiz_dev_prop__)
+        .def("add_wiz_class_prop",
+            (void (Tango::DeviceClass::*) (const std::string &, const std::string &))
+            add_wiz_class_prop_)
+        .def("add_wiz_class_prop",
+            (void (Tango::DeviceClass::*) (const std::string &, const std::string &, const std::string &))
+            add_wiz_class_prop__)
+        .def("_device_destroyer",
+            (void (Tango::DeviceClass::*) (const char *))
+            &Tango::DeviceClass::device_destroyer)
+
+        .def("_create_attribute", &CppDeviceClass::create_attribute)
+        .def("_create_command", &CppDeviceClass::create_command)
+    ;
+}
+
diff --git a/src/server/device_class.h b/src/server/device_class.h
new file mode 100644
index 0000000..da64ea3
--- /dev/null
+++ b/src/server/device_class.h
@@ -0,0 +1,175 @@
+#ifndef _DEVICE_CLASS_H_
+#define _DEVICE_CLASS_H_
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+class CppDeviceClass: public Tango::DeviceClass
+{
+public:
+    CppDeviceClass(const string &name)
+        :Tango::DeviceClass(const_cast<string&>(name))
+    {}
+
+    virtual ~CppDeviceClass()
+    {}
+
+    /**
+     * Export a device.
+     * Associate the servant to a CORBA object and send device network parameter
+     * to TANGO database.
+     * The main parameter sent to database is the CORBA object stringified device IOR.
+     *
+     * @param[in] dev The device to be exported (CORBA servant)
+     * @param[in] corba_dev_name The name to be used in the CORBA object key.
+     *                           This parameter does not need to be set in most of
+     *                           cases and has a default value. It is used for special
+     *                           device server like the database device server.
+     */
+    inline void export_device(Tango::DeviceImpl *dev, const char *corba_dev_nam = "Unused")
+    {
+        Tango::DeviceClass::export_device(dev, corba_dev_nam);
+    }
+
+    /**
+     * Returns the python interpreter state
+     *
+     * @return python interpreter state pointer
+     */
+    inline PyInterpreterState *get_py_interp()
+    {
+        return interp;
+    }
+
+    /**
+     * Sets the python interpreter state
+     *
+     * @param[in] in python interpreter state
+     */
+    inline void set_py_interp(PyInterpreterState *in)
+    {
+        interp = in;
+    }
+
+    /**
+     * Creates an attribute and adds it to the att_list.
+     * This method is intended to be called by python to register a new
+     * attribute.
+     */
+    void create_attribute(vector<Tango::Attr *> &att_list,
+                          const std::string &attr_name,
+                          Tango::CmdArgType attr_type,
+                          Tango::AttrDataFormat attr_format,
+                          Tango::AttrWriteType attr_write,
+                          long dim_x, long dim_y,
+                          Tango::DispLevel display_level,
+                          long polling_period,
+                          bool memorized, bool hw_memorized,
+                          const std::string &read_method_name,
+                          const std::string &write_method_name,
+                          const std::string &is_allowed_name,
+                          Tango::UserDefaultAttrProp &att_prop);
+
+    /**
+     * Creates a command.
+     * This method is intended to be called by python to register a new
+     * command.
+     */
+    void create_command(const std::string &cmd_name,
+                        Tango::CmdArgType param_type,
+                        Tango::CmdArgType result_type,
+                        const std::string &param_desc,
+                        const std::string &result_desc,
+                        Tango::DispLevel display_level,
+                        bool default_command, long polling_period,
+                        const std::string &is_allowed);
+
+protected:
+    PyInterpreterState *interp;
+};
+
+class CppDeviceClassWrap : public CppDeviceClass
+{
+public:
+
+    /** a reference to itself */
+    PyObject *m_self;
+
+    /**
+     * Constructor
+     *
+     * @param[in] self A reference to the python device class object
+     * @param[in] name the class name
+     */
+    CppDeviceClassWrap(PyObject *self, const std::string &name)
+        : CppDeviceClass(name), m_self(self)
+    {
+        init_class();
+    }
+
+    /**
+     * Destructor
+     */
+    virtual ~CppDeviceClassWrap()
+    {}
+
+    /**
+     * This method forward a C++ call to the device_factory method to the
+     * Python method
+     *
+     * @param[in] dev_list The device name list
+     */
+    virtual void device_factory(const Tango::DevVarStringArray *dev_list);
+
+    /**
+     * This method forward a C++ call to the attribute_factory method to the
+     * Python method
+     *
+     * @param[in] att_list attribute list
+     */
+    virtual void attribute_factory(std::vector<Tango::Attr *> &att_list);
+
+    /**
+     * This method forward a C++ call to the command_factory method to the
+     * Python method
+     */
+    virtual void command_factory();
+
+    /**
+     * This method is called to ask Python to delete a class by decrementing
+     * the Python ref count
+     */
+    virtual void delete_class();
+
+    /**
+     * This method forward a C++ call to the signal_handler method to the
+     * Python method or executes default signal handler if no signal handler
+     * is defined in python
+     *
+     * @param[in] signo signal identifier
+     */
+    virtual void signal_handler(long signo);
+
+    /**
+     * Default signal handler implementation
+     *
+     * @param[in] signo signal identifier
+     */
+    void default_signal_handler(long signo);
+
+protected:
+
+    /**
+     * Initializes the class. Registers as a python DeviceClass to tango,
+     * determines existence of a signal handler among other things
+     */
+    void init_class();
+
+    /**
+     * flag containing the information about the existence of a signal_handler
+     * method in the python class
+     */
+    bool signal_handler_defined;
+};
+
+#endif // _DEVICE_CLASS_H_
diff --git a/src/server/device_impl.cpp b/src/server/device_impl.cpp
new file mode 100644
index 0000000..f52e0f6
--- /dev/null
+++ b/src/server/device_impl.cpp
@@ -0,0 +1,1294 @@
+#include <boost/python.hpp>
+#include <boost/python/return_value_policy.hpp>
+#include <string>
+#include <tango.h>
+
+#include "defs.h"
+#include "pytgutils.h"
+#include "exception.h"
+#include "server/device_impl.h"
+#include "server/attr.h"
+#include "server/attribute.h"
+#include "to_py.h"
+
+extern const char *param_must_be_seq;
+
+using namespace boost::python;
+
+#define __AUX_DECL_CALL_DEVICE_METHOD \
+    AutoPythonGIL __py_lock;
+
+#define __AUX_CATCH_PY_EXCEPTION \
+    catch(boost::python::error_already_set &eas) \
+    { handle_python_exception(eas); }
+
+#define __AUX_CATCH_EXCEPTION(name) \
+    catch(...)                                                                \
+    { Tango::Except::throw_exception("CppException",                          \
+                                     "An unexpected C++ exception occurred",  \
+                                     #name );                                 \
+    }
+
+#define CALL_DEVICE_METHOD(cls, name) \
+    __AUX_DECL_CALL_DEVICE_METHOD \
+    try {                                                                     \
+        if (override name = this->get_override( #name) ) { name (); }         \
+        else { cls :: name (); }                                              \
+    }                                                                         \
+    __AUX_CATCH_PY_EXCEPTION \
+    __AUX_CATCH_EXCEPTION(name)
+
+#define CALL_DEVICE_METHOD_VARGS(cls, name, ...) \
+    __AUX_DECL_CALL_DEVICE_METHOD \
+    try {                                                                     \
+        if (override name = this->get_override( #name) )                      \
+        { name (__VA_ARGS__); }                                               \
+        else { cls :: name (__VA_ARGS__); }                                   \
+    }                                                                         \
+    __AUX_CATCH_PY_EXCEPTION \
+    __AUX_CATCH_EXCEPTION(name)
+
+#define CALL_DEVICE_METHOD_RET(cls, name) \
+    __AUX_DECL_CALL_DEVICE_METHOD \
+    try {                                                                     \
+        if (override name = this->get_override( #name) ) { return name (); }  \
+        else { return cls :: name (); }                                       \
+    }                                                                         \
+    __AUX_CATCH_PY_EXCEPTION \
+    __AUX_CATCH_EXCEPTION(name)
+
+#define CALL_DEVICE_METHOD_VARGS_RET(cls, name, ...) \
+    __AUX_DECL_CALL_DEVICE_METHOD \
+    try {                                                                     \
+        if (override name = this->get_override( #name) )                      \
+        { return name (__VA_ARGS__); }                                        \
+        else { return cls :: name (__VA_ARGS__); }                            \
+    }                                                                         \
+    __AUX_CATCH_PY_EXCEPTION \
+    __AUX_CATCH_EXCEPTION(name)
+
+#define SAFE_PUSH(dev, attr, attr_name) \
+    char *__att_name_ptr = PyString_AsString(attr_name.ptr()); \
+    AutoPythonAllowThreads python_guard_ptr; \
+    Tango::AutoTangoMonitor tango_guard(&dev); \
+    Tango::Attribute & attr = dev.get_device_attr()->get_attr_by_name(__att_name_ptr); \
+    python_guard_ptr.giveup();
+
+#define SAFE_PUSH_CHANGE_EVENT(dev, attr_name, data) \
+{ \
+    SAFE_PUSH(dev, attr, attr_name) \
+    PyAttribute::set_value(attr, data); \
+    attr.fire_change_event(); \
+}
+
+#define SAFE_PUSH_CHANGE_EVENT_VARGS(dev, attr_name, data, ...) \
+{ \
+    SAFE_PUSH(dev, attr, attr_name) \
+    PyAttribute::set_value(attr, data, __VA_ARGS__); \
+    attr.fire_change_event(); \
+}
+
+#define SAFE_PUSH_CHANGE_EVENT_DATE_QUALITY(dev, attr_name, data, date, quality) \
+{ \
+    SAFE_PUSH(dev, attr, attr_name) \
+    PyAttribute::set_value_date_quality(attr, data, date, quality); \
+    attr.fire_change_event(); \
+}
+
+#define SAFE_PUSH_CHANGE_EVENT_DATE_QUALITY_VARGS(dev, attr_name, data, date, quality, ...) \
+{ \
+    SAFE_PUSH(dev, attr, attr_name) \
+    PyAttribute::set_value_date_quality(attr, data, date, quality, __VA_ARGS__); \
+    attr.fire_change_event(); \
+}
+
+#define SAFE_PUSH_ARCHIVE_EVENT(dev, attr_name, data) \
+{ \
+    SAFE_PUSH(dev, attr, attr_name) \
+    PyAttribute::set_value(attr, data); \
+    attr.fire_archive_event(); \
+}
+
+#define SAFE_PUSH_ARCHIVE_EVENT_VARGS(dev, attr_name, data, ...) \
+{ \
+    SAFE_PUSH(dev, attr, attr_name) \
+    PyAttribute::set_value(attr, data, __VA_ARGS__); \
+    attr.fire_archive_event(); \
+}
+
+#define SAFE_PUSH_ARCHIVE_EVENT_DATE_QUALITY(dev, attr_name, data, date, quality) \
+{ \
+    SAFE_PUSH(dev, attr, attr_name) \
+    PyAttribute::set_value_date_quality(attr, data, date, quality); \
+    attr.fire_archive_event(); \
+}
+
+#define SAFE_PUSH_ARCHIVE_EVENT_DATE_QUALITY_VARGS(dev, attr_name, data, date, quality, ...) \
+{ \
+    SAFE_PUSH(dev, attr, attr_name) \
+    PyAttribute::set_value_date_quality(attr, data, date, quality, __VA_ARGS__); \
+    attr.fire_archive_event(); \
+}
+
+#define AUX_SAFE_PUSH_EVENT(dev, attr_name, filt_names, filt_vals) \
+    StdStringVector filt_names_; \
+    StdDoubleVector filt_vals_; \
+    from_sequence<StdStringVector>::convert(filt_names, filt_names_); \
+    from_sequence<StdDoubleVector>::convert(filt_vals, filt_vals_); \
+    SAFE_PUSH(dev, attr, attr_name)
+
+#define SAFE_PUSH_EVENT(dev, attr_name, filt_names, filt_vals, data) \
+{ \
+    AUX_SAFE_PUSH_EVENT(dev, attr_name, filt_names, filt_vals) \
+    PyAttribute::set_value(attr, data); \
+    attr.fire_event(filt_names_, filt_vals_); \
+}
+
+#define SAFE_PUSH_EVENT_VARGS(dev, attr_name, filt_names, filt_vals, data, ...) \
+{ \
+    AUX_SAFE_PUSH_EVENT(dev,attr_name, filt_names, filt_vals) \
+    PyAttribute::set_value(attr, data, __VA_ARGS__); \
+    attr.fire_event(filt_names_, filt_vals_); \
+}
+
+#define SAFE_PUSH_EVENT_DATE_QUALITY(dev, attr_name, filt_names, filt_vals, data, date, quality) \
+{ \
+    AUX_SAFE_PUSH_EVENT(dev, attr_name, filt_names, filt_vals) \
+    PyAttribute::set_value_date_quality(attr, data, date, quality); \
+    attr.fire_event(filt_names_, filt_vals_); \
+}
+
+#define SAFE_PUSH_EVENT_DATE_QUALITY_VARGS(dev, attr_name, filt_names, filt_vals, data, date, quality, ...) \
+{ \
+    AUX_SAFE_PUSH_EVENT(dev,attr_name, filt_names, filt_vals) \
+    PyAttribute::set_value_date_quality(attr, data, date, quality, __VA_ARGS__); \
+    attr.fire_event(filt_names_, filt_vals_); \
+}
+
+namespace PyDeviceImpl
+{
+    inline PyObject* get_polled_cmd(Tango::DeviceImpl &self)
+    {
+        return to_list<std::vector<std::string> >::convert(self.get_polled_cmd());
+    }
+
+    inline PyObject* get_polled_attr(Tango::DeviceImpl &self)
+    {
+        return to_list<std::vector<std::string> >::convert(self.get_polled_attr());
+    }
+    
+    inline PyObject* get_non_auto_polled_cmd(Tango::DeviceImpl &self)
+    {
+        return to_list<std::vector<std::string> >::convert(self.get_non_auto_polled_cmd());
+    }
+
+    inline PyObject* get_non_auto_polled_attr(Tango::DeviceImpl &self)
+    {
+        return to_list<std::vector<std::string> >::convert(self.get_non_auto_polled_attr());
+    }
+    
+    /* **********************************
+     * change event USING set_value
+     * **********************************/
+    inline void push_change_event(Tango::DeviceImpl &self, str &name)
+    {
+        str name_lower = name.lower();
+        if ("state" != name_lower && "status" != name_lower)
+        {
+            Tango::Except::throw_exception(
+                "PyDs_InvalidCall",
+                "push_change_event without data parameter is only allowed for "
+                "state and status attributes.", "DeviceImpl::push_change_event");
+        }
+        SAFE_PUSH(self, attr, name)
+        attr.fire_change_event();
+    }
+
+    inline void push_change_event(Tango::DeviceImpl &self, str &name, object &data)
+    {
+        boost::python::extract<Tango::DevFailed> except_convert(data);
+        if (except_convert.check()) {
+            SAFE_PUSH(self, attr, name);
+            attr.fire_change_event(
+                           const_cast<Tango::DevFailed*>( &except_convert() ));
+            return;
+        }
+        SAFE_PUSH_CHANGE_EVENT(self, name, data);
+    }
+
+    // Special variantion for encoded data type
+    inline void push_change_event(Tango::DeviceImpl &self, str &name, str &str_data,
+                                  str &data)
+    {
+        SAFE_PUSH(self, attr, name)
+        PyAttribute::set_value(attr, str_data, data);
+        attr.fire_change_event();
+    }
+
+    inline void push_change_event(Tango::DeviceImpl &self, str &name, object &data,
+                                  long x)
+    {
+        SAFE_PUSH_CHANGE_EVENT_VARGS(self, name, data, x);
+    }
+
+    inline void push_change_event(Tango::DeviceImpl &self, str &name, object &data,
+                                  long x, long y)
+    {
+        SAFE_PUSH_CHANGE_EVENT_VARGS(self, name, data, x, y);
+    }
+
+    /* **********************************
+     * change event USING set_value_date_quality
+     * **********************************/
+
+    inline void push_change_event(Tango::DeviceImpl &self, str &name, object &data,
+                                  double t, Tango::AttrQuality quality)
+    {
+        SAFE_PUSH_CHANGE_EVENT_DATE_QUALITY(self, name, data, t, quality)
+    }
+
+    // Special variantion for encoded data type
+    inline void push_change_event(Tango::DeviceImpl &self, str &name, str &str_data,
+                                  str &data, double t, Tango::AttrQuality quality)
+    {
+        SAFE_PUSH(self, attr, name)
+        PyAttribute::set_value_date_quality(attr, str_data, data, t, quality);
+        attr.fire_change_event();
+    }
+
+    inline void push_change_event(Tango::DeviceImpl &self, str &name, object &data,
+                                  double t, Tango::AttrQuality quality, long x)
+    {
+        SAFE_PUSH_CHANGE_EVENT_DATE_QUALITY_VARGS(self, name, data, t, quality, x)
+    }
+
+    inline void push_change_event(Tango::DeviceImpl &self, str &name, object &data,
+                                  double t, Tango::AttrQuality quality, long x, long y)
+    {
+        SAFE_PUSH_CHANGE_EVENT_DATE_QUALITY_VARGS(self, name, data, t, quality, x, y)
+    }
+
+    /* **********************************
+     * archive event USING set_value
+     * **********************************/
+    inline void push_archive_event(Tango::DeviceImpl &self, str &name)
+    {
+        SAFE_PUSH(self, attr, name)
+        attr.fire_archive_event();
+    }
+
+    inline void push_archive_event(Tango::DeviceImpl &self, str &name, object &data)
+    {
+        boost::python::extract<Tango::DevFailed> except_convert(data);
+        if (except_convert.check()) {
+            SAFE_PUSH(self, attr, name);
+            attr.fire_archive_event(
+                           const_cast<Tango::DevFailed*>( &except_convert() ));
+            return;
+        }
+        SAFE_PUSH_ARCHIVE_EVENT(self, name, data);
+    }
+
+    // Special variantion for encoded data type
+    inline void push_archive_event(Tango::DeviceImpl &self, str &name, str &str_data,
+                                   str &data)
+    {
+        SAFE_PUSH(self, attr, name)
+        PyAttribute::set_value(attr, str_data, data);
+        attr.fire_archive_event();
+    }
+
+    inline void push_archive_event(Tango::DeviceImpl &self, str &name, object &data,
+                           long x)
+    {
+        SAFE_PUSH_ARCHIVE_EVENT_VARGS(self, name, data, x);
+    }
+
+    inline void push_archive_event(Tango::DeviceImpl &self, str &name, object &data,
+                           long x, long y)
+    {
+        SAFE_PUSH_ARCHIVE_EVENT_VARGS(self, name, data, x, y);
+    }
+
+    /* **********************************
+     * archive event USING set_value_date_quality
+     * **********************************/
+
+    inline void push_archive_event(Tango::DeviceImpl &self, str &name, object &data,
+                                  double t, Tango::AttrQuality quality)
+    {
+        SAFE_PUSH_ARCHIVE_EVENT_DATE_QUALITY(self, name, data, t, quality)
+    }
+
+    // Special variantion for encoded data type
+    inline void push_archive_event(Tango::DeviceImpl &self, str &name, str &str_data,
+                                   str &data, double t, Tango::AttrQuality quality)
+    {
+        SAFE_PUSH(self, attr, name)
+        PyAttribute::set_value_date_quality(attr, str_data, data, t, quality);
+        attr.fire_archive_event();
+    }
+
+    inline void push_archive_event(Tango::DeviceImpl &self, str &name, object &data,
+                                  double t, Tango::AttrQuality quality, long x)
+    {
+        SAFE_PUSH_ARCHIVE_EVENT_DATE_QUALITY_VARGS(self, name, data, t, quality, x)
+    }
+
+    inline void push_archive_event(Tango::DeviceImpl &self, str &name, object &data,
+                                  double t, Tango::AttrQuality quality, long x, long y)
+    {
+        SAFE_PUSH_ARCHIVE_EVENT_DATE_QUALITY_VARGS(self, name, data, t, quality, x, y)
+    }
+
+    /* **********************************
+     * user event USING set_value
+     * **********************************/
+    inline void push_event(Tango::DeviceImpl &self, str &name,
+                           object &filt_names, object &filt_vals)
+    {
+        AUX_SAFE_PUSH_EVENT(self, name, filt_names, filt_vals)
+        attr.fire_event(filt_names_, filt_vals_);
+    }
+
+    inline void push_event(Tango::DeviceImpl &self, str &name,
+                           object &filt_names, object &filt_vals, object &data)
+    {
+        SAFE_PUSH_EVENT(self, name, filt_names, filt_vals, data)
+    }
+
+    // Special variantion for encoded data type
+    inline void push_event(Tango::DeviceImpl &self, str &name,
+                           object &filt_names, object &filt_vals,
+                           str &str_data, str &data)
+    {
+        AUX_SAFE_PUSH_EVENT(self, name, filt_names, filt_vals)
+        PyAttribute::set_value(attr, str_data, data);
+        attr.fire_event(filt_names_, filt_vals_);
+    }
+
+    inline void push_event(Tango::DeviceImpl &self, str &name,
+                           object &filt_names, object &filt_vals, object &data,
+                           long x)
+    {
+        SAFE_PUSH_EVENT_VARGS(self, name, filt_names, filt_vals, data, x)
+    }
+
+    inline void push_event(Tango::DeviceImpl &self, str &name,
+                           object &filt_names, object &filt_vals, object &data,
+                           long x, long y)
+    {
+        SAFE_PUSH_EVENT_VARGS(self, name, filt_names, filt_vals, data, x, y)
+    }
+
+    /* ***************************************
+     * user event USING set_value_date_quality
+     * **************************************/
+
+    inline void push_event(Tango::DeviceImpl &self, str &name,
+                           object &filt_names, object &filt_vals, object &data,
+                           double t, Tango::AttrQuality quality)
+    {
+        SAFE_PUSH_EVENT_DATE_QUALITY(self, name, filt_names, filt_vals, data, t, quality)
+    }
+
+    // Special variantion for encoded data type
+    inline void push_event(Tango::DeviceImpl &self, str &name,
+                           object &filt_names, object &filt_vals,
+                           str &str_data, str &data,
+                           double t, Tango::AttrQuality quality)
+    {
+        AUX_SAFE_PUSH_EVENT(self, name, filt_names, filt_vals)
+        PyAttribute::set_value_date_quality(attr, str_data, data, t, quality);
+        attr.fire_event(filt_names_, filt_vals_);
+    }
+
+    inline void push_event(Tango::DeviceImpl &self, str &name,
+                           object &filt_names, object &filt_vals, object &data,
+                           double t, Tango::AttrQuality quality, long x)
+    {
+        SAFE_PUSH_EVENT_DATE_QUALITY_VARGS(self, name, filt_names, filt_vals, data, t, quality, x)
+    }
+
+    inline void push_event(Tango::DeviceImpl &self, str &name,
+                           object &filt_names, object &filt_vals, object &data,
+                           double t, Tango::AttrQuality quality, long x, long y)
+    {
+        SAFE_PUSH_EVENT_DATE_QUALITY_VARGS(self, name, filt_names, filt_vals, data, t, quality, x, y)
+    }
+
+    void check_attribute_method_defined(PyObject *self,
+                                        const std::string &attr_name,
+                                        const std::string &method_name)
+    {
+        bool exists, is_method;
+
+        is_method_defined(self, method_name, exists, is_method);
+
+        if (!exists)
+        {
+            TangoSys_OMemStream o;
+            o << "Wrong definition of attribute " << attr_name
+              << "\nThe attribute method " << method_name
+              << " does not exist in your class!" << ends;
+
+            Tango::Except::throw_exception(
+                    (const char *)"PyDs_WrongCommandDefinition",
+                    o.str(),
+                    (const char *)"check_attribute_method_defined");
+        }
+
+        if(!is_method)
+        {
+            TangoSys_OMemStream o;
+            o << "Wrong definition of attribute " << attr_name
+              << "\nThe object " << method_name
+              << " exists in your class but is not a Python method" << ends;
+
+            Tango::Except::throw_exception(
+                    (const char *)"PyDs_WrongCommandDefinition",
+                    o.str(),
+                    (const char *)"check_attribute_method_defined");
+        }
+    }
+
+    void add_attribute(Tango::DeviceImpl &self, const Tango::Attr &c_new_attr)
+    {
+        Tango::Attr &new_attr = const_cast<Tango::Attr &>(c_new_attr);
+
+        std::string
+            attr_name = new_attr.get_name(),
+            is_allowed_method = "is_" + attr_name + "_allowed",
+            read_name_met = "read_" + attr_name,
+            write_name_met = "write_" + attr_name;
+
+        Tango::AttrWriteType attr_write = new_attr.get_writable();
+
+        //
+        // Create the attribute object according to attribute format
+        //
+
+        PyScaAttr *sca_attr_ptr = NULL;
+        PySpecAttr *spec_attr_ptr = NULL;
+        PyImaAttr *ima_attr_ptr= NULL;
+        PyAttr *py_attr_ptr = NULL;
+        Tango::Attr *attr_ptr = NULL;
+
+        long x, y;
+        vector<Tango::AttrProperty> &def_prop = new_attr.get_user_default_properties();
+        Tango::AttrDataFormat attr_format = new_attr.get_format();
+        long attr_type = new_attr.get_type();
+
+        switch (attr_format)
+        {
+            case Tango::SCALAR:
+                sca_attr_ptr = new PyScaAttr(attr_name, attr_type, attr_write, def_prop);
+                py_attr_ptr = sca_attr_ptr;
+                attr_ptr = sca_attr_ptr;
+                break;
+
+            case Tango::SPECTRUM:
+                x = (static_cast<Tango::SpectrumAttr &>(new_attr)).get_max_x();
+                spec_attr_ptr = new PySpecAttr(attr_name, attr_type, attr_write, x, def_prop);
+                py_attr_ptr = spec_attr_ptr;
+                attr_ptr = spec_attr_ptr;
+                break;
+
+            case Tango::IMAGE:
+                x = (static_cast<Tango::ImageAttr &>(new_attr)).get_max_x();
+                y = (static_cast<Tango::ImageAttr &>(new_attr)).get_max_y();
+                ima_attr_ptr = new PyImaAttr(attr_name, attr_type, attr_write, x, y, def_prop);
+                py_attr_ptr = ima_attr_ptr;
+                attr_ptr = ima_attr_ptr;
+                break;
+
+            default:
+                TangoSys_OMemStream o;
+                o << "Attribute " << attr_name << " has an unexpected data format\n"
+                  << "Please report this bug to the PyTango development team"
+                  << ends;
+                Tango::Except::throw_exception(
+                        (const char *)"PyDs_UnexpectedAttributeFormat",
+                        o.str(),
+                        (const char *)"cpp_add_attribute");
+                break;
+        }
+
+        py_attr_ptr->set_read_name(read_name_met);
+        py_attr_ptr->set_write_name(write_name_met);
+        py_attr_ptr->set_allowed_name(is_allowed_method);
+
+        //
+        // Install attribute in Tango.
+        //
+        self.add_attribute(attr_ptr);
+    }
+
+    void remove_attribute(Tango::DeviceImpl &self, const char *att_name)
+    {
+        string str(att_name);
+        self.remove_attribute(str, false);
+    }
+
+    inline void debug(Tango::DeviceImpl &self, const string &msg)
+    {
+        self.get_logger()->debug(msg);
+    }
+
+    inline void info(Tango::DeviceImpl &self, const string &msg)
+    {
+        self.get_logger()->info(msg);
+    }
+
+    inline void warn(Tango::DeviceImpl &self, const string &msg)
+    {
+        self.get_logger()->warn(msg);
+    }
+
+    inline void error(Tango::DeviceImpl &self, const string &msg)
+    {
+        self.get_logger()->error(msg);
+    }
+
+    inline void fatal(Tango::DeviceImpl &self, const string &msg)
+    {
+        self.get_logger()->fatal(msg);
+    }
+    
+    PyObject* get_attribute_config(Tango::DeviceImpl &self, object &py_attr_name_seq)
+    {
+        Tango::DevVarStringArray par;
+        convert2array(py_attr_name_seq, par);
+        
+        Tango::AttributeConfigList *attr_conf_list_ptr = 
+            self.get_attribute_config(par);
+        
+        boost::python::list ret = to_py(*attr_conf_list_ptr);
+        delete attr_conf_list_ptr;
+        
+        return boost::python::incref(ret.ptr());
+    }
+    
+    void set_attribute_config(Tango::DeviceImpl &self, object &py_attr_conf_list)
+    {
+        Tango::AttributeConfigList attr_conf_list;
+        from_py_object(py_attr_conf_list, attr_conf_list);
+        self.set_attribute_config(attr_conf_list);
+    }
+}
+
+DeviceImplWrap::DeviceImplWrap(PyObject *self, CppDeviceClass *cl,
+                               std::string &st)
+    :Tango::DeviceImpl(cl,st), m_self(self)
+{
+    Py_INCREF(m_self);
+}
+
+DeviceImplWrap::DeviceImplWrap(PyObject *self, CppDeviceClass *cl,
+                               const char *name,
+                               const char *desc /* = "A Tango device" */,
+                               Tango::DevState sta /* = Tango::UNKNOWN */,
+                               const char *status /* = StatusNotSet */)
+    :Tango::DeviceImpl(cl, name, desc, sta, status), m_self(self)
+{
+    Py_INCREF(m_self);
+}
+
+void DeviceImplWrap::init_device()
+{
+    this->get_override("init_device")();
+}
+
+Device_2ImplWrap::Device_2ImplWrap(PyObject *self, CppDeviceClass *cl,
+                                   std::string &st)
+    :Tango::Device_2Impl(cl,st),m_self(self)
+{
+    Py_INCREF(m_self);
+}
+
+Device_2ImplWrap::Device_2ImplWrap(PyObject *self, CppDeviceClass *cl,
+                                   const char *name,
+                                   const char *desc /* = "A Tango device" */,
+                                   Tango::DevState sta /* = Tango::UNKNOWN */,
+                                   const char *status /* = StatusNotSet */)
+    :Tango::Device_2Impl(cl, name, desc, sta, status), m_self(self)
+{
+    Py_INCREF(m_self);
+}
+
+void Device_2ImplWrap::init_device()
+{
+    this->get_override("init_device")();
+}
+
+PyDeviceImplBase::PyDeviceImplBase(PyObject *self):the_self(self)
+{
+    Py_INCREF(the_self);
+}
+
+namespace PyDevice_2Impl
+{
+    PyObject* get_attribute_config_2(Tango::Device_2Impl &self, object &attr_name_seq)
+    {
+        Tango::DevVarStringArray par;
+        convert2array(attr_name_seq, par);
+        
+        Tango::AttributeConfigList_2 *attr_conf_list_ptr = 
+            self.get_attribute_config_2(par);
+        
+        boost::python::list ret = to_py(*attr_conf_list_ptr);
+        delete attr_conf_list_ptr;
+        
+        return boost::python::incref(ret.ptr());
+    }
+
+    /* Postponed: Tango (7.1.1) has no set_attribute_config_2 !!!
+    void set_attribute_config_2(Tango::Device_2Impl &self, object &py_attr_conf_list)
+    {
+        Tango::AttributeConfigList_2 attr_conf_list;
+        from_py_object(py_attr_conf_list, attr_conf_list);
+        self.set_attribute_config_2(attr_conf_list);
+    }
+    */
+}
+
+PyDeviceImplBase::~PyDeviceImplBase()
+{}
+
+void PyDeviceImplBase::py_delete_dev()
+{
+    try
+    {
+        Py_DECREF(the_self);
+    }
+    catch(error_already_set &eas)
+    {
+        handle_python_exception(eas);
+    }
+}
+
+Device_3ImplWrap::Device_3ImplWrap(PyObject *self, CppDeviceClass *cl,
+                                   std::string &st)
+    :Tango::Device_3Impl(cl,st),
+    PyDeviceImplBase(self)
+{
+    _init();
+}
+
+Device_3ImplWrap::Device_3ImplWrap(PyObject *self, CppDeviceClass *cl,
+                                   const char *name,
+                                   const char *desc /* = "A Tango device" */,
+                                   Tango::DevState sta /* = Tango::UNKNOWN */,
+                                   const char *status /* = StatusNotSet */)
+    :Tango::Device_3Impl(cl, name, desc, sta, status),
+    PyDeviceImplBase(self)
+{
+    _init();
+}
+
+void Device_3ImplWrap::_init()
+{
+    // Make sure the wrapper contains a valid pointer to the self
+    // I found out this is needed by inspecting the boost wrapper_base.hpp code
+    initialize_wrapper(the_self, this);
+
+    // Tell Tango that this is a Python device.
+    // Humm, we should try to avoid this in the future
+    this->set_py_device(true);
+
+    Tango::Device_3ImplExt *tmp_ptr = ext_3;
+    Py_Device_3ImplExt *new_ext = new Py_Device_3ImplExt(this);
+    ext_3 = new_ext;
+    delete tmp_ptr;
+}
+
+void Device_3ImplWrap::init_device()
+{
+    AutoPythonGIL __py_lock;
+    try
+    {
+        this->get_override("init_device")();
+    }
+    catch(boost::python::error_already_set &eas)
+    {
+        handle_python_exception(eas);
+    }
+}
+
+void Device_3ImplWrap::delete_device()
+{
+    CALL_DEVICE_METHOD(Device_3Impl, delete_device)
+}
+
+void Device_3ImplWrap::default_delete_device()
+{
+    this->Tango::Device_3Impl::delete_device();
+}
+
+void Device_3ImplWrap::delete_dev()
+{
+    // Call here the delete_device method. It is defined in Device_3ImplWrap
+    // class which is already destroyed when the Tango kernel call the
+    // delete_device method
+    try
+    {
+        delete_device();
+    }
+    catch (Tango::DevFailed &e)
+    {
+        Tango::Except::print_exception(e);
+    }
+}
+
+void Device_3ImplWrap::py_delete_dev()
+{
+    Device_3ImplWrap::delete_dev();
+    PyDeviceImplBase::py_delete_dev();
+}
+
+void Device_3ImplWrap::always_executed_hook()
+{
+    CALL_DEVICE_METHOD(Device_3Impl, always_executed_hook)
+}
+
+void Device_3ImplWrap::default_always_executed_hook()
+{
+    this->Tango::Device_3Impl::always_executed_hook();
+}
+
+void Device_3ImplWrap::read_attr_hardware(vector<long> &attr_list)
+{
+    CALL_DEVICE_METHOD_VARGS(Device_3Impl, read_attr_hardware, attr_list)
+}
+
+void Device_3ImplWrap::default_read_attr_hardware(vector<long> &attr_list)
+{
+    this->Tango::Device_3Impl::read_attr_hardware(attr_list);
+}
+
+void Device_3ImplWrap::write_attr_hardware(vector<long> &attr_list)
+{
+    CALL_DEVICE_METHOD_VARGS(Device_3Impl, write_attr_hardware, attr_list)
+}
+
+void Device_3ImplWrap::default_write_attr_hardware(vector<long> &attr_list)
+{
+    this->Tango::Device_3Impl::write_attr_hardware(attr_list);
+}
+
+Tango::DevState Device_3ImplWrap::dev_state()
+{
+    CALL_DEVICE_METHOD_RET(Device_3Impl, dev_state)
+    // Keep the compiler quiet
+    return Tango::UNKNOWN;
+}
+
+Tango::DevState Device_3ImplWrap::default_dev_state()
+{
+    return this->Tango::Device_3Impl::dev_state();
+}
+
+Tango::ConstDevString Device_3ImplWrap::dev_status()
+{
+    CALL_DEVICE_METHOD_RET(Device_3Impl, dev_status)
+    // Keep the compiler quiet
+    return "Impossible state";
+}
+
+Tango::ConstDevString Device_3ImplWrap::default_dev_status()
+{
+    return this->Tango::Device_3Impl::dev_status();
+}
+
+void Device_3ImplWrap::signal_handler(long signo)
+{
+    CALL_DEVICE_METHOD_VARGS(Device_3Impl, signal_handler, signo)
+}
+
+void Device_3ImplWrap::default_signal_handler(long signo)
+{
+    this->Tango::Device_3Impl::signal_handler(signo);
+}
+
+namespace PyDevice_3Impl
+{
+    PyObject* get_attribute_config_3(Tango::Device_3Impl &self, object &attr_name_seq)
+    {
+        Tango::DevVarStringArray par;
+        convert2array(attr_name_seq, par);
+        
+        Tango::AttributeConfigList_3 *attr_conf_list_ptr = 
+            self.get_attribute_config_3(par);
+        
+        boost::python::list ret = to_py(*attr_conf_list_ptr);
+        delete attr_conf_list_ptr;
+        
+        return boost::python::incref(ret.ptr());
+    }
+    
+    void set_attribute_config_3(Tango::Device_3Impl &self, object &py_attr_conf_list)
+    {
+        Tango::AttributeConfigList_3 attr_conf_list;
+        from_py_object(py_attr_conf_list, attr_conf_list);
+        self.set_attribute_config_3(attr_conf_list);
+    }
+
+}
+
+Device_4ImplWrap::Device_4ImplWrap(PyObject *self, CppDeviceClass *cl,
+                                   std::string &st)
+    :Tango::Device_4Impl(cl,st),
+    PyDeviceImplBase(self)
+{
+    _init();
+}
+
+Device_4ImplWrap::Device_4ImplWrap(PyObject *self, CppDeviceClass *cl,
+                                   const char *name,
+                                   const char *desc /* = "A Tango device" */,
+                                   Tango::DevState sta /* = Tango::UNKNOWN */,
+                                   const char *status /* = StatusNotSet */)
+    :Tango::Device_4Impl(cl, name, desc, sta, status),
+    PyDeviceImplBase(self)
+{
+    _init();
+}
+
+void Device_4ImplWrap::_init()
+{
+    // Make sure the wrapper contains a valid pointer to the self
+    // I found out this is needed by inspecting the boost wrapper_base.hpp code
+    initialize_wrapper(the_self, this);
+
+    // Tell Tango that this is a Python device.
+    // Humm, we should try to avoid this in the future
+    this->set_py_device(true);
+
+    Tango::Device_3ImplExt *tmp_ptr = ext_3;
+    Py_Device_3ImplExt *new_ext = new Py_Device_3ImplExt(this);
+    ext_3 = new_ext;
+    delete tmp_ptr;
+}
+
+void Device_4ImplWrap::init_device()
+{
+    AutoPythonGIL __py_lock;
+    try
+    {
+        this->get_override("init_device")();
+    }
+    catch(boost::python::error_already_set &eas)
+    {
+        handle_python_exception(eas);
+    }
+}
+
+void Device_4ImplWrap::delete_device()
+{
+    CALL_DEVICE_METHOD(Device_4Impl, delete_device)
+}
+
+void Device_4ImplWrap::default_delete_device()
+{
+    this->Tango::Device_4Impl::delete_device();
+}
+
+void Device_4ImplWrap::delete_dev()
+{
+    // Call here the delete_device method. It is defined in Device_4ImplWrap
+    // class which is already destroyed when the Tango kernel call the
+    // delete_device method
+    try
+    {
+        delete_device();
+    }
+    catch (Tango::DevFailed &e)
+    {
+        Tango::Except::print_exception(e);
+    }
+}
+
+void Device_4ImplWrap::py_delete_dev()
+{
+    Device_4ImplWrap::delete_dev();
+    PyDeviceImplBase::py_delete_dev();
+}
+
+void Device_4ImplWrap::always_executed_hook()
+{
+    CALL_DEVICE_METHOD(Device_4Impl, always_executed_hook)
+}
+
+void Device_4ImplWrap::default_always_executed_hook()
+{
+    this->Tango::Device_4Impl::always_executed_hook();
+}
+
+void Device_4ImplWrap::read_attr_hardware(vector<long> &attr_list)
+{
+    CALL_DEVICE_METHOD_VARGS(Device_4Impl, read_attr_hardware, attr_list)
+}
+
+void Device_4ImplWrap::default_read_attr_hardware(vector<long> &attr_list)
+{
+    this->Tango::Device_4Impl::read_attr_hardware(attr_list);
+}
+
+void Device_4ImplWrap::write_attr_hardware(vector<long> &attr_list)
+{
+    CALL_DEVICE_METHOD_VARGS(Device_4Impl, write_attr_hardware, attr_list)
+}
+
+void Device_4ImplWrap::default_write_attr_hardware(vector<long> &attr_list)
+{
+    this->Tango::Device_4Impl::write_attr_hardware(attr_list);
+}
+
+Tango::DevState Device_4ImplWrap::dev_state()
+{
+    CALL_DEVICE_METHOD_RET(Device_4Impl, dev_state)
+    // Keep the compiler quiet
+    return Tango::UNKNOWN;
+}
+
+Tango::DevState Device_4ImplWrap::default_dev_state()
+{
+    return this->Tango::Device_4Impl::dev_state();
+}
+
+Tango::ConstDevString Device_4ImplWrap::dev_status()
+{
+    CALL_DEVICE_METHOD_RET(Device_4Impl, dev_status)
+    // Keep the compiler quiet
+    return "Impossible state";
+}
+
+Tango::ConstDevString Device_4ImplWrap::default_dev_status()
+{
+    return this->Tango::Device_4Impl::dev_status();
+}
+
+void Device_4ImplWrap::signal_handler(long signo)
+{
+    try
+    {
+        CALL_DEVICE_METHOD_VARGS(Device_4Impl, signal_handler, signo)
+    }
+    catch(Tango::DevFailed &df)
+    {
+        long nb_err = df.errors.length();
+        df.errors.length(nb_err + 1);
+        
+        df.errors[nb_err].reason = CORBA::string_dup(
+            "PyDs_UnmanagedSignalHandlerException");
+        df.errors[nb_err].desc = CORBA::string_dup(
+            "An unmanaged Tango::DevFailed exception occurred in signal_handler");
+        df.errors[nb_err].origin = CORBA::string_dup("Device_4Impl.signal_handler");
+        df.errors[nb_err].severity = Tango::ERR;
+
+        Tango::Except::print_exception(df);
+    }
+}
+
+void Device_4ImplWrap::default_signal_handler(long signo)
+{
+    this->Tango::Device_4Impl::signal_handler(signo);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Ext
+///////////////////////////////////////////////////////////////////////////////
+
+Py_Device_3ImplExt::Py_Device_3ImplExt(PyDeviceImplBase *ptr)
+    :Tango::Device_3ImplExt(), my_dev(ptr)
+{}
+
+Py_Device_3ImplExt::~Py_Device_3ImplExt()
+{}
+
+void Py_Device_3ImplExt::delete_dev()
+{
+    my_dev->py_delete_dev();
+}
+
+#if ((defined sun) || (defined WIN32))
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(register_signal_overload,
+                                       Tango::DeviceImpl::register_signal, 1, 1)
+#else
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(register_signal_overload,
+                                       Tango::DeviceImpl::register_signal, 1, 2)
+#endif
+
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(append_status_overload,
+                                       Tango::DeviceImpl::append_status, 1, 2)
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(set_change_event_overload,
+                                       Tango::DeviceImpl::set_change_event, 2, 3)
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(set_archive_event_overload,
+                                       Tango::DeviceImpl::set_archive_event, 2, 3)
+
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(push_data_ready_event_overload,
+                                       Tango::DeviceImpl::push_data_ready_event, 1, 2)
+
+
+void export_device_impl()
+{
+ 
+    // The following function declarations are necessary to be able to cast
+    // the function parameters from string& to const string&, otherwise python
+    // will not recognize the method calls
+    long (Tango::DeviceImpl::*get_cmd_poll_ring_depth_)(std::string &) =
+        &Tango::DeviceImpl::get_cmd_poll_ring_depth;
+    long (Tango::DeviceImpl::*get_attr_poll_ring_depth_)(std::string &) =
+        &Tango::DeviceImpl::get_attr_poll_ring_depth;
+
+    
+    void (Tango::DeviceImpl::*stop_polling1)() = &Tango::DeviceImpl::stop_polling;
+    void (Tango::DeviceImpl::*stop_polling2)(bool) = &Tango::DeviceImpl::stop_polling;
+    
+    class_<Tango::DeviceImpl, DeviceImplWrap, boost::noncopyable>("DeviceImpl",
+        init<CppDeviceClass *, const char *,
+             optional<const char *, Tango::DevState, const char *> >())
+
+        .def("init_device", pure_virtual(&Tango::DeviceImpl::init_device))
+        .def("set_state", &Tango::DeviceImpl::set_state)
+        .def("get_state", &Tango::DeviceImpl::get_state,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_prev_state", &Tango::DeviceImpl::get_prev_state,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_name", &Tango::DeviceImpl::get_name,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_device_attr", &Tango::DeviceImpl::get_device_attr,
+            return_value_policy<reference_existing_object>())
+        .def("register_signal",
+            &Tango::DeviceImpl::register_signal,
+            register_signal_overload())
+        .def("unregister_signal", &Tango::DeviceImpl::unregister_signal)
+        .def("get_status", &Tango::DeviceImpl::get_status,
+            return_value_policy<copy_non_const_reference>())
+        .def("set_status", &Tango::DeviceImpl::set_status)
+        .def("append_status", &Tango::DeviceImpl::append_status,
+            append_status_overload())
+        .def("dev_state", &Tango::DeviceImpl::dev_state)
+        .def("dev_status", &Tango::DeviceImpl::dev_status)
+        .def("get_attribute_config", &PyDeviceImpl::get_attribute_config)
+        .def("set_change_event",
+            &Tango::DeviceImpl::set_change_event,
+            set_change_event_overload())
+        .def("set_archive_event",
+            &Tango::DeviceImpl::set_archive_event,
+            set_archive_event_overload())
+        .def("_add_attribute", &PyDeviceImpl::add_attribute)
+        .def("_remove_attribute", &PyDeviceImpl::remove_attribute)
+        //@TODO .def("get_device_class")
+        //@TODO .def("get_device_attr")
+        //@TODO .def("get_db_device")
+        
+        
+        .def("get_exported_flag", &Tango::DeviceImpl::get_exported_flag)
+        .def("get_poll_ring_depth", &Tango::DeviceImpl::get_poll_ring_depth)
+        .def("get_poll_old_factor", &Tango::DeviceImpl::get_poll_old_factor)
+        .def("is_polled", (bool (Tango::DeviceImpl::*) ())&Tango::DeviceImpl::is_polled)
+        .def("get_polled_cmd", &PyDeviceImpl::get_polled_cmd)
+        .def("get_polled_attr", &PyDeviceImpl::get_polled_attr)
+        .def("get_non_auto_polled_cmd", &PyDeviceImpl::get_non_auto_polled_cmd)
+        .def("get_non_auto_polled_attr", &PyDeviceImpl::get_non_auto_polled_attr)
+        //@TODO .def("get_poll_obj_list", &PyDeviceImpl::get_poll_obj_list)
+        .def("stop_polling", stop_polling1)
+        .def("stop_polling", stop_polling2)
+        .def("check_command_exists", &Tango::DeviceImpl::check_command_exists)
+        //@TODO .def("get_command", &PyDeviceImpl::get_command)
+        .def("get_dev_idl_version", &Tango::DeviceImpl::get_dev_idl_version)
+        .def("get_cmd_poll_ring_depth",
+            (long (Tango::DeviceImpl::*) (const std::string &))
+            get_cmd_poll_ring_depth_)
+        .def("get_attr_poll_ring_depth",
+            (long (Tango::DeviceImpl::*) (const std::string &))
+            get_attr_poll_ring_depth_)
+        .def("is_device_locked", &Tango::DeviceImpl::is_device_locked)
+        
+        .def("init_logger", &Tango::DeviceImpl::init_logger)
+        .def("start_logging", &Tango::DeviceImpl::start_logging)
+        .def("stop_logging", &Tango::DeviceImpl::stop_logging)
+        
+        //.def("set_exported_flag", &Tango::DeviceImpl::set_exported_flag)
+        //.def("set_poll_ring_depth", &Tango::DeviceImpl::set_poll_ring_depth)
+
+        .def("push_change_event",
+            (void (*) (Tango::DeviceImpl &, str &))
+            &PyDeviceImpl::push_change_event,
+            (arg_("self"), arg_("attr_name")))
+
+        .def("push_change_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &))
+            &PyDeviceImpl::push_change_event)
+
+        .def("push_change_event",
+            (void (*) (Tango::DeviceImpl &, str &, str &, str &))
+            &PyDeviceImpl::push_change_event)
+
+        .def("push_change_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, long))
+            &PyDeviceImpl::push_change_event)
+
+        .def("push_change_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, long, long))
+            &PyDeviceImpl::push_change_event)
+
+        .def("push_change_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, double, Tango::AttrQuality))
+            &PyDeviceImpl::push_change_event)
+
+        .def("push_change_event",
+            (void (*) (Tango::DeviceImpl &, str &, str &, str &, double, Tango::AttrQuality))
+            &PyDeviceImpl::push_change_event)
+
+        .def("push_change_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, double, Tango::AttrQuality, long))
+            &PyDeviceImpl::push_change_event)
+
+        .def("push_change_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, double, Tango::AttrQuality, long, long))
+            &PyDeviceImpl::push_change_event)
+
+        .def("push_archive_event",
+            (void (*) (Tango::DeviceImpl &, str &))
+            &PyDeviceImpl::push_archive_event,
+            (arg_("self"), arg_("attr_name")))
+
+        .def("push_archive_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &))
+            &PyDeviceImpl::push_archive_event)
+
+        .def("push_archive_event",
+            (void (*) (Tango::DeviceImpl &, str &, str &, str &))
+            &PyDeviceImpl::push_archive_event)
+
+        .def("push_archive_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, long))
+            &PyDeviceImpl::push_archive_event)
+
+        .def("push_archive_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, long, long))
+            &PyDeviceImpl::push_archive_event)
+
+        .def("push_archive_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, double, Tango::AttrQuality))
+            &PyDeviceImpl::push_archive_event)
+
+        .def("push_archive_event",
+            (void (*) (Tango::DeviceImpl &, str &, str &, str &, double, Tango::AttrQuality))
+            &PyDeviceImpl::push_archive_event)
+
+        .def("push_archive_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, double, Tango::AttrQuality, long))
+            &PyDeviceImpl::push_archive_event)
+
+        .def("push_archive_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, double, Tango::AttrQuality, long, long))
+            &PyDeviceImpl::push_archive_event)
+
+        .def("push_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, object &))
+            &PyDeviceImpl::push_event)
+
+        .def("push_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, object &, object &))
+            &PyDeviceImpl::push_event)
+
+        .def("push_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, object &, str &, str &))
+            &PyDeviceImpl::push_event)
+
+        .def("push_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, object &, object &, long))
+            &PyDeviceImpl::push_event)
+
+        .def("push_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, object &, object &, long, long))
+            &PyDeviceImpl::push_event)
+
+        .def("push_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, object &, object &, double, Tango::AttrQuality))
+            &PyDeviceImpl::push_event)
+
+        .def("push_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, object &, str &, str &, double, Tango::AttrQuality))
+            &PyDeviceImpl::push_event)
+
+        .def("push_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, object &, object &, double, Tango::AttrQuality, long))
+            &PyDeviceImpl::push_event)
+
+        .def("push_event",
+            (void (*) (Tango::DeviceImpl &, str &, object &, object &, object &, double, Tango::AttrQuality, long, long))
+            &PyDeviceImpl::push_event)
+
+        .def("push_data_ready_event", &Tango::DeviceImpl::push_data_ready_event,
+            push_data_ready_event_overload())
+
+        .def("get_logger", &Tango::DeviceImpl::get_logger, return_internal_reference<>())
+        .def("__debug_stream", &PyDeviceImpl::debug)
+        .def("__info_stream", &PyDeviceImpl::info)
+        .def("__warn_stream", &PyDeviceImpl::warn)
+        .def("__error_stream", &PyDeviceImpl::error)
+        .def("__fatal_stream", &PyDeviceImpl::fatal)
+    ;
+
+    class_<Tango::Device_2Impl, Device_2ImplWrap,
+           bases<Tango::DeviceImpl>,
+           boost::noncopyable>
+           ("Device_2Impl",
+            init<CppDeviceClass *, const char *,
+                 optional<const char *, Tango::DevState, const char *> >())
+        .def("get_attribute_config_2", &PyDevice_2Impl::get_attribute_config_2)
+        //@TODO .def("read_attribute_history_2", &PyDevice_2Impl::read_attribute_history_2)
+    ;
+
+    class_<Tango::Device_3Impl, Device_3ImplWrap,
+           bases<Tango::Device_2Impl>,
+           boost::noncopyable>
+           ("Device_3Impl",
+            init<CppDeviceClass *, const char *,
+                 optional<const char *, Tango::DevState, const char *> >())
+        .def("init_device", pure_virtual(&Tango::Device_3Impl::init_device))
+        .def("delete_device", &Tango::Device_3Impl::delete_device,
+            &Device_3ImplWrap::default_delete_device)
+        .def("always_executed_hook", &Tango::Device_3Impl::always_executed_hook,
+            &Device_3ImplWrap::default_always_executed_hook)
+        .def("read_attr_hardware", &Tango::Device_3Impl::read_attr_hardware,
+            &Device_3ImplWrap::default_read_attr_hardware)
+        .def("write_attr_hardware", &Tango::Device_3Impl::write_attr_hardware,
+            &Device_3ImplWrap::default_write_attr_hardware)
+        .def("dev_state", &Tango::Device_3Impl::dev_state,
+            &Device_3ImplWrap::default_dev_state)
+        .def("dev_status", &Tango::Device_3Impl::dev_status,
+            &Device_3ImplWrap::default_dev_status)
+        .def("signal_handler", &Tango::Device_3Impl::signal_handler,
+            &Device_3ImplWrap::default_signal_handler)
+        .def("get_attribute_config_3", &PyDevice_3Impl::get_attribute_config_3)
+        .def("set_attribute_config_3", &PyDevice_3Impl::set_attribute_config_3)
+    ;
+
+    class_<Tango::Device_4Impl, Device_4ImplWrap,
+           bases<Tango::Device_3Impl>,
+           boost::noncopyable>
+           ("Device_4Impl",
+            init<CppDeviceClass *, const char *,
+                 optional<const char *, Tango::DevState, const char *> >())
+        .def("init_device", pure_virtual(&Tango::Device_4Impl::init_device))
+        .def("delete_device", &Tango::Device_4Impl::delete_device,
+            &Device_4ImplWrap::default_delete_device)
+        .def("always_executed_hook", &Tango::Device_4Impl::always_executed_hook,
+            &Device_4ImplWrap::default_always_executed_hook)
+        .def("read_attr_hardware", &Tango::Device_4Impl::read_attr_hardware,
+            &Device_4ImplWrap::default_read_attr_hardware)
+        .def("write_attr_hardware", &Tango::Device_4Impl::write_attr_hardware,
+            &Device_4ImplWrap::default_write_attr_hardware)
+        .def("dev_state", &Tango::Device_4Impl::dev_state,
+            &Device_4ImplWrap::default_dev_state)
+        .def("dev_status", &Tango::Device_4Impl::dev_status,
+            &Device_4ImplWrap::default_dev_status)
+        .def("signal_handler", &Tango::Device_4Impl::signal_handler,
+            &Device_4ImplWrap::default_signal_handler)
+    ;
+}
diff --git a/src/server/device_impl.h b/src/server/device_impl.h
new file mode 100644
index 0000000..43cdbb6
--- /dev/null
+++ b/src/server/device_impl.h
@@ -0,0 +1,428 @@
+#ifndef _DEVICE_IMPL_H
+#define _DEVICE_IMPL_H
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+#include <server/device_class.h>
+
+/**
+ * A wrapper around the Tango::DeviceImpl class
+ */
+class DeviceImplWrap : public Tango::DeviceImpl,
+                       public boost::python::wrapper<Tango::DeviceImpl>
+{
+public:
+    /** a reference to itself */
+    PyObject *m_self;
+
+    /**
+     * Constructor
+     *
+     * @param[in] self
+     * @param[in] cl
+     * @param[in] st
+     */
+    DeviceImplWrap(PyObject *self, CppDeviceClass *cl, std::string &st);
+
+    /**
+     * Constructor
+     *
+     * @param[in] self
+     * @param[in] cl
+     * @param[in] name
+     * @param[in] desc
+     * @param[in] sta
+     * @param[in] status
+     */
+    DeviceImplWrap(PyObject *self, CppDeviceClass *cl, const char *name,
+                   const char *desc = "A Tango device",
+                   Tango::DevState sta = Tango::UNKNOWN,
+                   const char *status = StatusNotSet);
+
+    /**
+     * Destructor
+     */
+    virtual ~DeviceImplWrap()
+    {}
+
+    /**
+     * Invokes the actual init_device
+     */
+    void init_device();
+};
+
+/**
+ * A wrapper around the Tango::Device_2Impl class
+ */
+class Device_2ImplWrap : public Tango::Device_2Impl,
+                         public boost::python::wrapper<Tango::Device_2Impl>
+{
+public:
+    /** a reference to itself */
+    PyObject *m_self;
+
+    /**
+     * Constructor
+     *
+     * @param[in] self
+     * @param[in] cl
+     * @param[in] st
+     */
+    Device_2ImplWrap(PyObject *self, CppDeviceClass *cl, std::string &st);
+
+    /**
+     * Constructor
+     *
+     * @param[in] self
+     * @param[in] cl
+     * @param[in] name
+     * @param[in] desc
+     * @param[in] sta
+     * @param[in] status
+     */
+    Device_2ImplWrap(PyObject *self, CppDeviceClass *cl, const char *name,
+                     const char *desc = "A Tango device",
+                     Tango::DevState sta = Tango::UNKNOWN,
+                     const char *status = StatusNotSet);
+
+    /**
+     * Destructor
+     */
+    virtual ~Device_2ImplWrap()
+    {}
+
+    /**
+     * Invokes the actual init_device
+     */
+    void init_device();
+};
+
+class PyDeviceImplBase
+{
+public:
+    /** a reference to itself */
+    PyObject *the_self;
+
+    PyDeviceImplBase(PyObject *self);
+
+    virtual ~PyDeviceImplBase();
+
+    virtual void py_delete_dev();
+};
+
+/**
+ * A wrapper around the Tango::Device_3Impl class
+ */
+class Device_3ImplWrap : public Tango::Device_3Impl,
+                         public PyDeviceImplBase,
+                         public boost::python::wrapper<Tango::Device_3Impl>
+{
+public:
+    /**
+     * Constructor
+     *
+     * @param[in] self
+     * @param[in] cl
+     * @param[in] st
+     */
+    Device_3ImplWrap(PyObject *self, CppDeviceClass *cl, std::string &st);
+
+    /**
+     * Constructor
+     *
+     * @param[in] self
+     * @param[in] cl
+     * @param[in] name
+     * @param[in] desc
+     * @param[in] sta
+     * @param[in] status
+     */
+    Device_3ImplWrap(PyObject *self, CppDeviceClass *cl, const char *name,
+                     const char *desc = "A Tango device",
+                     Tango::DevState sta = Tango::UNKNOWN,
+                     const char *status = StatusNotSet);
+
+    /**
+     * A wrapper around the add_attribute in order to process some
+     * internal information
+     *
+     * @param att the attribute reference containning information about
+     *            the new attribute to be added
+     */
+    void _add_attribute(const Tango::Attr &att);
+
+    /**
+     * Wrapper around the remove_attribute in order to simplify
+     * string & to const string & conversion and default parameters
+     */
+    void _remove_attribute(const char *att_name);
+
+    /**
+     * Destructor
+     */
+    virtual ~Device_3ImplWrap()
+    {}
+
+    /**
+     * Necessary init_device implementation to call python
+     */
+    virtual void init_device();
+
+    /**
+     * Necessary delete_device implementation to call python
+     */
+    virtual void delete_device();
+
+    /**
+     * Executes default delete_device implementation
+     */
+    void default_delete_device();
+
+    /**
+     * called to ask Python to delete a device by decrementing the Python
+     * reference count
+     */
+    virtual void delete_dev();
+
+    /**
+     * Necessary always_executed_hook implementation to call python
+     */
+    virtual void always_executed_hook();
+
+    /**
+     * Executes default always_executed_hook implementation
+     */
+    void default_always_executed_hook();
+
+    /**
+     * Necessary read_attr_hardware implementation to call python
+     */
+    virtual void read_attr_hardware(vector<long> &attr_list);
+
+    /**
+     * Executes default read_attr_hardware implementation
+     */
+    void default_read_attr_hardware(vector<long> &attr_list);
+
+    /**
+     * Necessary write_attr_hardware implementation to call python
+     */
+    virtual void write_attr_hardware(vector<long> &attr_list);
+
+    /**
+     * Executes default write_attr_hardware implementation
+     */
+    void default_write_attr_hardware(vector<long> &attr_list);
+
+    /**
+     * Necessary dev_state implementation to call python
+     */
+    virtual Tango::DevState dev_state();
+
+    /**
+     * Executes default dev_state implementation
+     */
+    Tango::DevState default_dev_state();
+
+    /**
+     * Necessary dev_status implementation to call python
+     */
+    virtual Tango::ConstDevString dev_status();
+
+    /**
+     * Executes default dev_status implementation
+     */
+    Tango::ConstDevString default_dev_status();
+
+    /**
+     * Necessary signal_handler implementation to call python
+     */
+    virtual void signal_handler(long signo);
+
+    /**
+     * Executes default signal_handler implementation
+     */
+    void default_signal_handler(long signo);
+
+    virtual void py_delete_dev();
+
+protected:
+    /**
+     * internal method used to initialize the class. Called by the constructors
+     */
+    void _init();
+};
+
+/**
+ * Device_4ImplWrap is the class used to represent a Python Tango device.
+ */
+class Device_4ImplWrap : public Tango::Device_4Impl,
+                         public PyDeviceImplBase,
+                         public boost::python::wrapper<Tango::Device_4Impl>
+{
+public:
+    /**
+     * Constructor
+     *
+     * @param[in] self
+     * @param[in] cl
+     * @param[in] st
+     */
+    Device_4ImplWrap(PyObject *self, CppDeviceClass *cl, std::string &st);
+
+    /**
+     * Constructor
+     *
+     * @param[in] self
+     * @param[in] cl
+     * @param[in] name
+     * @param[in] desc
+     * @param[in] sta
+     * @param[in] status
+     */
+    Device_4ImplWrap(PyObject *self, CppDeviceClass *cl, const char *name,
+                     const char *desc = "A Tango device",
+                     Tango::DevState sta = Tango::UNKNOWN,
+                     const char *status = StatusNotSet);
+
+    /**
+     * Destructor
+     */
+    virtual ~Device_4ImplWrap()
+    {}
+
+    /**
+     * A wrapper around the add_attribute in order to process some
+     * internal information
+     *
+     * @param att the attribute reference containning information about
+     *            the new attribute to be added
+     */
+    void _add_attribute(const Tango::Attr &att);
+
+    /**
+     * Wrapper around the remove_attribute in order to simplify
+     * string & to const string & conversion and default parameters
+     */
+    void _remove_attribute(const char *att_name);
+
+    /**
+     * Necessary init_device implementation to call python
+     */
+    virtual void init_device();
+
+    /**
+     * Necessary delete_device implementation to call python
+     */
+    virtual void delete_device();
+
+    /**
+     * Executes default delete_device implementation
+     */
+    void default_delete_device();
+
+    /**
+     * called to ask Python to delete a device by decrementing the Python
+     * reference count
+     */
+    virtual void delete_dev();
+
+    /**
+     * Necessary always_executed_hook implementation to call python
+     */
+    virtual void always_executed_hook();
+
+    /**
+     * Executes default always_executed_hook implementation
+     */
+    void default_always_executed_hook();
+
+    /**
+     * Necessary read_attr_hardware implementation to call python
+     */
+    virtual void read_attr_hardware(vector<long> &attr_list);
+
+    /**
+     * Executes default read_attr_hardware implementation
+     */
+    void default_read_attr_hardware(vector<long> &attr_list);
+
+    /**
+     * Necessary write_attr_hardware implementation to call python
+     */
+    virtual void write_attr_hardware(vector<long> &attr_list);
+
+    /**
+     * Executes default write_attr_hardware implementation
+     */
+    void default_write_attr_hardware(vector<long> &attr_list);
+
+    /**
+     * Necessary dev_state implementation to call python
+     */
+    virtual Tango::DevState dev_state();
+
+    /**
+     * Executes default dev_state implementation
+     */
+    Tango::DevState default_dev_state();
+
+    /**
+     * Necessary dev_status implementation to call python
+     */
+    virtual Tango::ConstDevString dev_status();
+
+    /**
+     * Executes default dev_status implementation
+     */
+    Tango::ConstDevString default_dev_status();
+
+    /**
+     * Necessary signal_handler implementation to call python
+     */
+    virtual void signal_handler(long signo);
+
+    /**
+     * Executes default signal_handler implementation
+     */
+    void default_signal_handler(long signo);
+
+    virtual void py_delete_dev();
+
+protected:
+    /**
+     * internal method used to initialize the class. Called by the constructors
+     */
+    void _init();
+};
+
+/**
+ * Device_3Impl extension wrapper
+ */
+class Py_Device_3ImplExt:public Tango::Device_3ImplExt
+{
+public:
+    /** pointer to pytango wrapper */
+    PyDeviceImplBase *my_dev;
+
+    /**
+     * Constructor
+     *
+     * @param[in] ptr Device_4Impl wrapper pointer
+     */
+    Py_Device_3ImplExt(PyDeviceImplBase *ptr);
+
+    /**
+     * Destructor
+     */
+    virtual ~Py_Device_3ImplExt();
+
+    /**
+     * overwrite of delete_dev method
+     */
+    virtual void delete_dev();
+
+};
+
+#endif // _DEVICE_IMPL_H
diff --git a/src/server/dserver.cpp b/src/server/dserver.cpp
new file mode 100644
index 0000000..7478783
--- /dev/null
+++ b/src/server/dserver.cpp
@@ -0,0 +1,181 @@
+#include <boost/python.hpp>
+#include <tango.h>
+
+#include "to_py.h"
+#include "from_py.h"
+
+using namespace boost::python;
+
+namespace PyDServer
+{
+    PyObject* query_class(Tango::DServer &self)
+    {
+        Tango::DevVarStringArray *res = self.query_class();
+        PyObject *py_res = CORBA_sequence_to_list<Tango::DevVarStringArray>::convert(*res);
+        delete res;
+        return py_res;
+    }
+    
+    PyObject* query_device(Tango::DServer &self)
+    {
+        Tango::DevVarStringArray *res = self.query_device();
+        PyObject *py_res = CORBA_sequence_to_list<Tango::DevVarStringArray>::convert(*res);
+        delete res;
+        return py_res;
+    }
+    
+    PyObject* query_sub_device(Tango::DServer &self)
+    {
+        Tango::DevVarStringArray *res = self.query_sub_device();
+        PyObject *py_res = CORBA_sequence_to_list<Tango::DevVarStringArray>::convert(*res);
+        delete res;
+        return py_res;
+    }
+    
+    PyObject* query_class_prop(Tango::DServer &self, const std::string &class_name)
+    {
+        std::string class_name2 = class_name;
+        Tango::DevVarStringArray *res = self.query_class_prop(class_name2);
+        PyObject *py_res = CORBA_sequence_to_list<Tango::DevVarStringArray>::convert(*res);
+        delete res;
+        return py_res;
+    }
+
+    PyObject* query_dev_prop(Tango::DServer &self, const std::string &dev_name)
+    {
+        std::string dev_name2 = dev_name;
+        Tango::DevVarStringArray *res = self.query_dev_prop(dev_name2);
+        PyObject *py_res = CORBA_sequence_to_list<Tango::DevVarStringArray>::convert(*res);
+        delete res;
+        return py_res;
+    }
+    
+    PyObject* polled_device(Tango::DServer &self)
+    {
+        Tango::DevVarStringArray *res = self.polled_device();
+        PyObject *py_res = CORBA_sequence_to_list<Tango::DevVarStringArray>::convert(*res);
+        delete res;
+        return py_res;
+    }
+    
+    PyObject* dev_poll_status(Tango::DServer &self, const std::string &dev_name)
+    {
+        std::string dev_name2 = dev_name;
+        Tango::DevVarStringArray *res = self.dev_poll_status(dev_name2);
+        PyObject *py_res = CORBA_sequence_to_list<Tango::DevVarStringArray>::convert(*res);
+        delete res;
+        return py_res;
+    }
+    
+    void add_obj_polling(Tango::DServer &self, object &py_long_str_array, bool with_db_upd = true, int delta_ms = 0)
+    {
+        Tango::DevVarLongStringArray long_str_array;
+        convert2array(py_long_str_array, long_str_array);
+        self.add_obj_polling(&long_str_array, with_db_upd, delta_ms);
+    }
+    
+    void upd_obj_polling_period(Tango::DServer &self, object &py_long_str_array, bool with_db_upd = true)
+    {
+        Tango::DevVarLongStringArray long_str_array;
+        convert2array(py_long_str_array, long_str_array);
+        self.upd_obj_polling_period(&long_str_array, with_db_upd);
+    }
+    
+    void rem_obj_polling(Tango::DServer &self, object &py_str_array, bool with_db_upd = true)
+    {
+        Tango::DevVarStringArray str_array;
+        convert2array(py_str_array, str_array);
+        self.rem_obj_polling(&str_array, with_db_upd);
+    }
+    
+    void lock_device(Tango::DServer &self, object &py_long_str_array)
+    {
+        Tango::DevVarLongStringArray long_str_array;
+        convert2array(py_long_str_array, long_str_array);
+        self.lock_device(&long_str_array);
+    }
+    
+    Tango::DevLong un_lock_device(Tango::DServer &self, object &py_long_str_array)
+    {
+        Tango::DevVarLongStringArray long_str_array;
+        convert2array(py_long_str_array, long_str_array);
+        return self.un_lock_device(&long_str_array);
+    }
+    
+    void re_lock_devices(Tango::DServer &self, object &py_str_array)
+    {
+        Tango::DevVarStringArray str_array;
+        convert2array(py_str_array, str_array);
+        self.re_lock_devices(&str_array);
+    }
+    
+    PyObject* dev_lock_status(Tango::DServer &self, Tango::ConstDevString dev_name)
+    {
+        Tango::DevVarLongStringArray* ret = self.dev_lock_status(dev_name);
+        PyObject* py_ret = 
+            CORBA_sequence_to_list<Tango::DevVarLongStringArray>::convert(*ret);
+        delete ret;
+        return py_ret;
+    }
+}
+
+BOOST_PYTHON_FUNCTION_OVERLOADS(add_obj_polling_overload, PyDServer::add_obj_polling, 2, 4)
+BOOST_PYTHON_FUNCTION_OVERLOADS(upd_obj_polling_period_overload, PyDServer::upd_obj_polling_period, 2, 3)
+BOOST_PYTHON_FUNCTION_OVERLOADS(rem_obj_polling_overload, PyDServer::rem_obj_polling, 2, 3)
+
+void export_dserver()
+{
+    // The following function declarations are necessary to be able to cast
+    // the function parameters from string& to const string&, otherwise python
+    // will not recognize the method calls
+
+    void (Tango::DServer::*restart_)(std::string &) = &Tango::DServer::restart;
+
+    class_<Tango::DServer,
+        bases<Tango::Device_4Impl>, boost::noncopyable>
+        ("DServer", no_init)
+        .def("query_class",  &PyDServer::query_class)
+        .def("query_device",  &PyDServer::query_device)
+        .def("query_sub_device",  &PyDServer::query_sub_device)
+        .def("kill", &Tango::DServer::kill)
+        .def("restart", 
+            (void (Tango::DServer::*) (const std::string &)) restart_)
+        .def("restart_server", &Tango::DServer::restart_server)
+        .def("query_class_prop", &PyDServer::query_class_prop)
+        .def("query_dev_prop", &PyDServer::query_dev_prop)
+        .def("polled_device", &PyDServer::polled_device)
+        .def("dev_poll_status", &PyDServer::polled_device)
+        .def("add_obj_polling", &PyDServer::add_obj_polling, 
+            add_obj_polling_overload())
+        .def("upd_obj_polling_period", &PyDServer::upd_obj_polling_period, 
+            upd_obj_polling_period_overload())
+        .def("rem_obj_polling", &PyDServer::rem_obj_polling, 
+            rem_obj_polling_overload())
+        .def("stop_polling", &Tango::DServer::stop_polling)
+        .def("start_polling", 
+            (void (Tango::DServer::*)() ) &Tango::DServer::start_polling)
+        .def("add_event_heartbeat", &Tango::DServer::add_event_heartbeat)
+        .def("rem_event_heartbeat", &Tango::DServer::rem_event_heartbeat)
+        .def("lock_device", &PyDServer::lock_device)
+        .def("un_lock_device", &PyDServer::un_lock_device)
+        .def("re_lock_devices", &PyDServer::re_lock_devices)
+        .def("dev_lock_status", &PyDServer::dev_lock_status)
+        .def("delete_devices", &Tango::DServer::delete_devices)
+        .def("start_logging", &Tango::DServer::start_logging)
+        .def("stop_logging", &Tango::DServer::stop_logging)
+        .def("get_process_name", &Tango::DServer::get_process_name,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_personal_name", &Tango::DServer::get_personal_name,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_instance_name", &Tango::DServer::get_instance_name,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_full_name", &Tango::DServer::get_full_name,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_fqdn", &Tango::DServer::get_fqdn,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_poll_th_pool_size", &Tango::DServer::get_poll_th_pool_size)
+        .def("get_opt_pool_usage", &Tango::DServer::get_opt_pool_usage)
+        .def("get_poll_th_conf", &Tango::DServer::get_poll_th_conf)
+    ;
+    
+}
diff --git a/src/server/log4tango.cpp b/src/server/log4tango.cpp
new file mode 100644
index 0000000..7e0e6c4
--- /dev/null
+++ b/src/server/log4tango.cpp
@@ -0,0 +1,123 @@
+#include <boost/python.hpp>
+#include <tango.h>
+
+#include "defs.h"
+#include "pytgutils.h"
+
+using namespace boost::python;
+
+extern const char *param_must_be_seq;
+extern const char *non_string_seq;
+
+namespace PyLogging
+{
+    void add_logging_target(object &obj)
+    {
+        PyObject *obj_ptr = obj.ptr();
+        if(PySequence_Check(obj_ptr) == 0)
+        {
+            raise_(PyExc_TypeError, param_must_be_seq);
+        }
+
+        Tango::DevVarStringArray par;
+        int len = (int) PySequence_Length(obj_ptr);
+        par.length(len);
+        for(int i = 0; i < len; ++i)
+        {
+            par[i] = CORBA::string_dup(PyString_AsString(PySequence_GetItem(obj_ptr, i)));
+        }
+        Tango::Logging::add_logging_target(&par);
+    }
+
+    void remove_logging_target(object &obj)
+    {
+        PyObject *obj_ptr = obj.ptr();
+        if(PySequence_Check(obj_ptr) == 0)
+        {
+            raise_(PyExc_TypeError, param_must_be_seq);
+        }
+
+        Tango::DevVarStringArray par;
+        int len = (int) PySequence_Length(obj_ptr);
+        par.length(len);
+        for(int i = 0; i < len; ++i)
+        {
+            par[i] = CORBA::string_dup(PyString_AsString(PySequence_GetItem(obj_ptr, i)));
+        }
+        Tango::Logging::remove_logging_target(&par);
+    }
+}
+
+void export_log4tango()
+{
+    {
+        scope level_scope =
+            class_<log4tango::Level, boost::noncopyable>("Level", no_init)
+
+            .def("get_name", &log4tango::Level::get_name,
+            return_value_policy<copy_const_reference>())
+            .def("get_value", &log4tango::Level::get_value)
+            .staticmethod("get_name")
+            .staticmethod("get_value")
+        ;
+
+        enum_<log4tango::Level::LevelLevel>("LevelLevel")
+            .value("OFF", log4tango::Level::OFF)
+            .value("FATAL", log4tango::Level::FATAL)
+            .value("ERROR", log4tango::Level::ERROR)
+            .value("WARN", log4tango::Level::WARN)
+            .value("INFO", log4tango::Level::INFO)
+            .value("DEBUG", log4tango::Level::DEBUG)
+        ;
+    }
+
+    class_<log4tango::Logger, boost::noncopyable>("Logger",
+        init<const std::string &, optional<log4tango::Level::Value> >())
+
+        .def("get_name", &log4tango::Logger::get_name,
+            return_value_policy<copy_const_reference>())
+        .def("set_level", &log4tango::Logger::set_level)
+        .def("get_level", &log4tango::Logger::get_level)
+        .def("is_level_enabled", &log4tango::Logger::is_level_enabled)
+        .def("__log",
+            (void (log4tango::Logger::*)(log4tango::Level::Value, const std::string &))
+            &log4tango::Logger::log)
+        .def("__log_unconditionally",
+            (void (log4tango::Logger::*)(log4tango::Level::Value, const std::string &))
+            &log4tango::Logger::log_unconditionally)
+        .def("__debug",
+            (void (log4tango::Logger::*)(const std::string &))
+            &log4tango::Logger::debug)
+        .def("__info",
+            (void (log4tango::Logger::*)(const std::string &))
+            &log4tango::Logger::info)
+        .def("__warn",
+            (void (log4tango::Logger::*)(const std::string &))
+            &log4tango::Logger::warn)
+        .def("__error",
+            (void (log4tango::Logger::*)(const std::string &))
+            &log4tango::Logger::error)
+        .def("__fatal",
+            (void (log4tango::Logger::*)(const std::string &))
+            &log4tango::Logger::fatal)
+        .def("is_debug_enabled", &log4tango::Logger::is_debug_enabled)
+        .def("is_info_enabled", &log4tango::Logger::is_info_enabled)
+        .def("is_warn_enabled", &log4tango::Logger::is_warn_enabled)
+        .def("is_error_enabled", &log4tango::Logger::is_error_enabled)
+        .def("is_fatal_enabled", &log4tango::Logger::is_fatal_enabled)
+    ;
+
+    class_<Tango::Logging, boost::noncopyable>("Logging", no_init)
+        .def("get_core_logger", &Tango::Logging::get_core_logger,
+            return_value_policy<reference_existing_object>())
+        .def("add_logging_target", &PyLogging::add_logging_target)
+        .def("remove_logging_target", &PyLogging::remove_logging_target)
+        .def("start_logging", &Tango::Logging::start_logging)
+        .def("stop_logging", &Tango::Logging::stop_logging)
+        .staticmethod("get_core_logger")
+        .staticmethod("add_logging_target")
+        .staticmethod("remove_logging_target")
+        .staticmethod("start_logging")
+        .staticmethod("stop_logging")
+    ;
+}
diff --git a/src/server/multi_attribute.cpp b/src/server/multi_attribute.cpp
new file mode 100644
index 0000000..0a37094
--- /dev/null
+++ b/src/server/multi_attribute.cpp
@@ -0,0 +1,34 @@
+#include "pytgutils.h"
+#include <sstream>
+
+using namespace boost::python;
+
+void export_multi_attribute()
+{
+    class_<Tango::MultiAttribute, boost::noncopyable>("MultiAttribute", no_init)
+        .def("get_attr_by_name", &Tango::MultiAttribute::get_attr_by_name,
+            return_value_policy<reference_existing_object>())
+        .def("get_attr_by_ind", &Tango::MultiAttribute::get_attr_by_ind,
+            return_value_policy<reference_existing_object>())
+        .def("get_w_attr_by_name", &Tango::MultiAttribute::get_w_attr_by_name,
+            return_value_policy<reference_existing_object>())
+        .def("get_w_attr_by_ind", &Tango::MultiAttribute::get_w_attr_by_ind,
+            return_value_policy<reference_existing_object>())
+        .def("get_attr_ind_by_name", &Tango::MultiAttribute::get_attr_ind_by_name) // New in 7.0.0
+        .def("get_alarm_list", &Tango::MultiAttribute::get_alarm_list,
+            return_internal_reference<>()) // New in 7.0.0
+        .def("get_attr_nb", &Tango::MultiAttribute::get_attr_nb) // New in 7.0.0
+        .def("check_alarm",
+            (bool (Tango::MultiAttribute::*) ())
+            &Tango::MultiAttribute::check_alarm) // New in 7.0.0
+        .def("check_alarm",
+            (bool (Tango::MultiAttribute::*) (const long))
+            &Tango::MultiAttribute::check_alarm) // New in 7.0.0
+        .def("check_alarm",
+            (bool (Tango::MultiAttribute::*) (const char *))
+            &Tango::MultiAttribute::check_alarm) // New in 7.0.0
+        .def("read_alarm",
+            (void (Tango::MultiAttribute::*) (const std::string &))
+            &Tango::MultiAttribute::read_alarm) // New in 7.0.0
+    ;
+}
diff --git a/src/server/subdev.cpp b/src/server/subdev.cpp
new file mode 100644
index 0000000..08449b3
--- /dev/null
+++ b/src/server/subdev.cpp
@@ -0,0 +1,37 @@
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+namespace PySubDevDiag
+{
+    PyObject *get_sub_devices(Tango::SubDevDiag &self)
+    {
+        Tango::DevVarStringArray *sub_devs = self.get_sub_devices();
+        
+        boost::python::list py_sub_devs;
+        for(unsigned long i = 0; i < sub_devs->length(); ++i)
+        {
+            py_sub_devs.append((*sub_devs)[i].in());
+        }
+        delete sub_devs;
+        return boost::python::incref(py_sub_devs.ptr());
+    }
+}
+
+void export_sub_dev_diag()
+{
+    class_<Tango::SubDevDiag, boost::noncopyable>
+        ("SubDevDiag", no_init)
+        .def("set_associated_device", &Tango::SubDevDiag::set_associated_device)
+        .def("get_associated_device", &Tango::SubDevDiag::get_associated_device)
+        .def("register_sub_device", &Tango::SubDevDiag::register_sub_device)
+        .def("remove_sub_devices", (void (Tango::SubDevDiag::*) ())
+            &Tango::SubDevDiag::remove_sub_devices)
+        .def("remove_sub_devices", (void (Tango::SubDevDiag::*) (std::string))
+            &Tango::SubDevDiag::remove_sub_devices)
+        .def("get_sub_devices", &PySubDevDiag::get_sub_devices)
+        .def("store_sub_devices", &Tango::SubDevDiag::store_sub_devices)
+        .def("get_sub_devices_from_cache", &Tango::SubDevDiag::get_sub_devices_from_cache)
+    ;
+}
diff --git a/src/server/tango_util.cpp b/src/server/tango_util.cpp
new file mode 100644
index 0000000..e82cbe1
--- /dev/null
+++ b/src/server/tango_util.cpp
@@ -0,0 +1,260 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+#include <iostream>
+
+#include "defs.h"
+#include "pytgutils.h"
+#include "exception.h"
+
+#include "server/device_class.h"
+
+using namespace boost::python;
+
+/// @todo GET RID OF THIS!! I HATE "HERE_OLD_TANGO___"
+#ifndef WIN32
+# define HERE_OLD_TANGO___
+#endif
+
+#ifdef HERE_OLD_TANGO___
+    void Tango::DServer::class_factory()
+    {
+        Tango::DServer* dserver = this;
+#else
+namespace PyUtil
+{
+    void _class_factory(Tango::DServer* dserver)
+    {
+#endif
+        AutoPythonGIL guard;
+        PYTANGO_MOD
+
+    //
+    // First, create CPP class if any. Their names are defined in a Python list
+    //
+        boost::python::list cpp_class_list =
+            extract<boost::python::list>(pytango.attr("get_cpp_classes")());
+        int cl_len = len(cpp_class_list);
+        for(int i = 0; i < cl_len; ++i)
+        {
+            tuple class_info = extract<tuple>(cpp_class_list[i]);
+            char *class_name = extract<char *>(class_info[0]);
+            char *par_name   = extract<char *>(class_info[1]);
+            dserver->create_cpp_class(class_name, par_name);
+        }
+
+    //
+    // Create Python classes with a call to the class_factory Python function
+    //
+        pytango.attr("class_factory")();
+
+    //
+    // Make all Python tango class(es) known to C++ and set the PyInterpreter state
+    //
+        boost::python::list constructed_classes(pytango.attr("get_constructed_classes")());
+        int cc_len = len(constructed_classes);
+        for(int i = 0; i < cc_len; ++i)
+        {
+            CppDeviceClass *cpp_dc = extract<CppDeviceClass *> (constructed_classes[i])();
+            dserver->add_class(cpp_dc);
+        }
+    }
+
+#ifdef HERE_OLD_TANGO___
+namespace PyUtil
+{
+    void server_init(Tango::Util & instance, bool with_window = false)
+    {
+        AutoPythonAllowThreads guard;
+        instance.server_init(with_window);
+    }
+#else
+    void server_init(Tango::Util & instance, bool with_window = false)
+    {
+        AutoPythonAllowThreads guard;
+        instance.set_class_factory_cb(_class_factory);
+        instance.server_init(with_window);
+    }
+#endif
+
+    void server_run(Tango::Util & instance)
+    {
+        AutoPythonAllowThreads guard;
+        instance.server_run();
+    }
+
+    inline Tango::Util* init(boost::python::object &obj)
+    {
+        PyObject *obj_ptr = obj.ptr();
+        if(PySequence_Check(obj_ptr) == 0)
+        {
+            raise_(PyExc_TypeError, param_must_be_seq);
+        }
+
+        int argc = (int) PySequence_Length(obj_ptr);
+        char** argv = new char*[argc];
+        Tango::Util* res = 0;
+
+        try {
+
+            for(int i = 0; i < argc; ++i)
+            {
+                argv[i] = PyString_AsString(PySequence_GetItem(obj_ptr, i));
+            }
+            res = Tango::Util::init(argc, argv);
+        } catch (...) {
+            delete [] argv;
+            throw;
+        }
+        delete [] argv;
+        return res;
+    }
+
+    inline Tango::Util* instance1()
+    {
+        return Tango::Util::instance();
+    }
+
+    inline Tango::Util* instance2(bool b)
+    {
+        return Tango::Util::instance(b);
+    }
+
+    inline object get_device_list_by_class(Tango::Util &self, const string &class_name)
+    {
+        boost::python::list py_dev_list;
+        vector<Tango::DeviceImpl *> &dev_list = self.get_device_list_by_class(class_name);
+        for(vector<Tango::DeviceImpl *>::iterator it = dev_list.begin(); it != dev_list.end(); ++it)
+        {
+            object py_value = object(
+                        handle<>(
+                            to_python_indirect<
+                                Tango::DeviceImpl*,
+                                detail::make_reference_holder>()(*it)));
+            
+            py_dev_list.append(py_value);
+        }
+        return py_dev_list;
+    }
+
+    inline object get_device_by_name(Tango::Util &self, const string &dev_name)
+    {
+        Tango::DeviceImpl *value = self.get_device_by_name(dev_name);
+        object py_value = object(
+                    handle<>(
+                        to_python_indirect<
+                            Tango::DeviceImpl*,
+                            detail::make_reference_holder>()(value)));
+
+        return py_value;
+    }
+    
+    inline object get_device_list(Tango::Util &self, const string &name)
+    {
+        boost::python::list py_dev_list;
+        vector<Tango::DeviceImpl *> dev_list = self.get_device_list(name);
+        for(vector<Tango::DeviceImpl *>::iterator it = dev_list.begin(); it != dev_list.end(); ++it)
+        {
+            object py_value = object(
+                        handle<>(
+                            to_python_indirect<
+                                Tango::DeviceImpl*,
+                                detail::make_reference_holder>()(*it)));
+            py_dev_list.append(py_value);
+        }
+        return py_dev_list;
+    }
+}
+
+void init_python()
+{
+    if (PyEval_ThreadsInitialized() == 0)
+    {
+        PyEval_InitThreads();
+    }
+}
+
+BOOST_PYTHON_FUNCTION_OVERLOADS (server_init_overload, PyUtil::server_init, 1, 2)
+
+void export_util()
+{
+    class_<Tango::Util, boost::noncopyable>("_Util", no_init)
+        .def("init", PyUtil::init,
+            return_value_policy<reference_existing_object>())
+        .staticmethod("init")
+
+        .def("instance", &PyUtil::instance1,
+            return_value_policy<reference_existing_object>())
+        .def("instance", &PyUtil::instance2,
+            return_value_policy<reference_existing_object>())
+        .staticmethod("instance")
+
+        .def("set_trace_level", &Tango::Util::set_trace_level)
+        .def("get_trace_level", &Tango::Util::get_trace_level)
+        .def("get_ds_inst_name", &Tango::Util::get_ds_inst_name,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_ds_exec_name", &Tango::Util::get_ds_exec_name,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_ds_name", &Tango::Util::get_ds_name,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_host_name", &Tango::Util::get_host_name,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_pid_str", &Tango::Util::get_pid_str,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_pid", &Tango::Util::get_pid)
+        .def("get_tango_lib_release", &Tango::Util::get_tango_lib_release)
+        .def("get_version_str", &Tango::Util::get_version_str,
+            return_value_policy<copy_non_const_reference>())
+        .def("get_server_version", &Tango::Util::get_server_version,
+            return_value_policy<copy_non_const_reference>())
+        .def("set_server_version", &Tango::Util::set_server_version)
+        .def("set_serial_model", &Tango::Util::set_serial_model)
+        .def("get_serial_model", &Tango::Util::get_serial_model)
+        .def("reset_filedatabase", &Tango::Util::reset_filedatabase)
+        .def("unregister_server", &Tango::Util::unregister_server)
+        .def("get_dserver_device", &Tango::Util::get_dserver_device,
+            return_value_policy<reference_existing_object>())
+        .def("server_init", &PyUtil::server_init, server_init_overload())
+        .def("server_run", &PyUtil::server_run)
+        .def("trigger_cmd_polling", &Tango::Util::trigger_cmd_polling)
+        .def("trigger_attr_polling", &Tango::Util::trigger_attr_polling)
+        .def("set_polling_threads_pool_size", &Tango::Util::set_polling_threads_pool_size)
+        .def("get_polling_threads_pool_size", &Tango::Util::get_polling_threads_pool_size)
+        .def("get_sub_dev_diag", &Tango::Util::get_sub_dev_diag,
+            return_internal_reference<>())
+        .def("connect_db", &Tango::Util::connect_db)
+        .def("reset_filedatabase", &Tango::Util::reset_filedatabase)
+        .def("get_database", &Tango::Util::get_database, 
+            return_internal_reference<>())
+        .def("unregister_server", &Tango::Util::unregister_server)
+        .def("get_device_list_by_class", &PyUtil::get_device_list_by_class)
+        .def("get_device_by_name", &PyUtil::get_device_by_name)
+        .def("get_device_list", &PyUtil::get_device_list)
+        .def_readonly("_UseDb", &Tango::Util::_UseDb)
+        .def_readonly("_FileDb", &Tango::Util::_FileDb)
+        .def("init_python", init_python)
+        .staticmethod("init_python")
+    ;
+}
diff --git a/src/server/user_default_attr_prop.cpp b/src/server/user_default_attr_prop.cpp
new file mode 100644
index 0000000..f9e03b6
--- /dev/null
+++ b/src/server/user_default_attr_prop.cpp
@@ -0,0 +1,32 @@
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_user_default_attr_prop()
+{
+    class_<Tango::UserDefaultAttrProp, boost::noncopyable>("UserDefaultAttrProp")
+        .def("set_label", &Tango::UserDefaultAttrProp::set_label)
+        .def("set_description", &Tango::UserDefaultAttrProp::set_description)
+        .def("set_format", &Tango::UserDefaultAttrProp::set_format)
+        .def("set_unit", &Tango::UserDefaultAttrProp::set_unit)
+        .def("set_standard_unit", &Tango::UserDefaultAttrProp::set_standard_unit)
+        .def("set_display_unit", &Tango::UserDefaultAttrProp::set_display_unit)
+        .def("set_min_value", &Tango::UserDefaultAttrProp::set_min_value)
+        .def("set_max_value", &Tango::UserDefaultAttrProp::set_max_value)
+        .def("set_min_alarm", &Tango::UserDefaultAttrProp::set_min_alarm)
+        .def("set_max_alarm", &Tango::UserDefaultAttrProp::set_max_alarm)
+        .def("set_min_warning", &Tango::UserDefaultAttrProp::set_min_warning)
+        .def("set_max_warning", &Tango::UserDefaultAttrProp::set_max_warning)
+        .def("set_delta_t", &Tango::UserDefaultAttrProp::set_delta_t)
+        .def("set_delta_val", &Tango::UserDefaultAttrProp::set_delta_val)
+        .def("set_abs_change", &Tango::UserDefaultAttrProp::set_abs_change)
+        .def("set_rel_change", &Tango::UserDefaultAttrProp::set_rel_change)
+        .def("set_period", &Tango::UserDefaultAttrProp::set_period)
+        .def("set_archive_abs_change", &Tango::UserDefaultAttrProp::set_archive_abs_change)
+        .def("set_archive_rel_change", &Tango::UserDefaultAttrProp::set_archive_rel_change)
+        .def("set_archive_period", &Tango::UserDefaultAttrProp::set_archive_period)
+    ;
+
+}
+
diff --git a/src/server/wattribute.cpp b/src/server/wattribute.cpp
new file mode 100644
index 0000000..1a98d22
--- /dev/null
+++ b/src/server/wattribute.cpp
@@ -0,0 +1,562 @@
+#include <boost/python.hpp>
+#include <boost/python/return_value_policy.hpp>
+#include <string>
+#include <tango.h>
+
+#include "defs.h"
+#include "pytgutils.h"
+#include "fast_from_py.h"
+
+using namespace boost::python;
+
+/**
+ * Helper method to Limit the max number of element to send to C++
+ *
+ * @param[in,out] len the length. if x*y is lower the len, the len is updated to x*y
+ * @param[in] x the x dimension
+ * @param[in] y the y dimension
+ */
+static inline void twod2oned(long &len, long x, long y)
+{
+    if (y <= 0)
+    {
+        if (x < len)
+        {
+            len = x;
+        }
+    }
+    else
+    {
+        long max_elt = x * y;
+        if (max_elt < len)
+            len = max_elt;
+    }
+}
+
+inline static void throw_wrong_python_data_type(const std::string &att_name,
+                                         const char *method)
+{
+    TangoSys_OMemStream o;
+    o << "Wrong Python type for attribute " << att_name << ends;
+    Tango::Except::throw_exception(
+            "PyDs_WrongPythonDataTypeForAttribute",
+            o.str(),
+            method);
+}
+
+namespace PyWAttribute
+{
+/// @name Min/Max value
+/// @{
+    template<long tangoTypeConst>
+    PyObject* __get_min_value(Tango::WAttribute &att)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+
+        TangoScalarType tg_val;
+        att.get_min_value(tg_val);
+        boost::python::object py_value(tg_val);
+
+        return boost::python::incref(py_value.ptr());
+    }
+
+    PyObject *get_min_value(Tango::WAttribute &att)
+    {
+        long type = att.get_data_type();
+
+        TANGO_DO_ON_NUMERICAL_ATTRIBUTE_DATA_TYPE(type,
+            return __get_min_value<tangoTypeConst>(att)
+        );
+        return 0;
+    }
+
+    template<long tangoTypeConst>
+    PyObject* __get_max_value(Tango::WAttribute &att)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+
+        TangoScalarType tg_val;
+        att.get_max_value(tg_val);
+        boost::python::object py_value(tg_val);
+        return boost::python::incref(py_value.ptr());
+    }
+
+    PyObject *get_max_value(Tango::WAttribute &att)
+    {
+        long type = att.get_data_type();
+
+        TANGO_DO_ON_NUMERICAL_ATTRIBUTE_DATA_TYPE(type,
+            return __get_max_value<tangoTypeConst>(att)
+        );
+        return 0;
+    }
+
+    template<long tangoTypeConst>
+    void __set_min_value(Tango::WAttribute &att, boost::python::object &v)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+
+        TangoScalarType tg_val = boost::python::extract<TangoScalarType>(v);
+
+        att.set_min_value(tg_val);
+    }
+
+    void set_min_value(Tango::WAttribute &att, boost::python::object &v)
+    {
+        long type = att.get_data_type();
+        TANGO_CALL_ON_NUMERICAL_ATTRIBUTE_DATA_TYPE(type, __set_min_value, att, v);
+    }
+
+    template<long tangoTypeConst>
+    void __set_max_value(Tango::WAttribute &att, boost::python::object &v)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+
+        TangoScalarType tg_val = boost::python::extract<TangoScalarType>(v);
+
+        att.set_max_value(tg_val);
+    }
+
+    void set_max_value(Tango::WAttribute &att, boost::python::object &v)
+    {
+        long type = att.get_data_type();
+        TANGO_CALL_ON_NUMERICAL_ATTRIBUTE_DATA_TYPE(type, __set_max_value, att, v);
+    }
+/// @}
+
+/// @name set_write_value
+/// @{
+
+    template<long tangoTypeConst>
+    inline void __set_write_value_scalar(Tango::WAttribute &att,
+                                         boost::python::object &value)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+        extract<TangoScalarType> val(value.ptr());
+        if (!val.check())
+        {
+            throw_wrong_python_data_type(att.get_name(), "set_write_value()");
+        }
+        TangoScalarType cpp_val = val;
+        att.set_write_value(cpp_val);
+    }
+
+    template<>
+    inline void __set_write_value_scalar<Tango::DEV_ENCODED>(Tango::WAttribute &att,
+                                                             boost::python::object &value)
+    {
+        Tango::Except::throw_exception(
+                "PyDs_WrongPythonDataTypeForAttribute",
+                "set_write_value is not supported for DEV_ENCODED attributes.",
+                "set_write_value()");
+    }
+
+    template<long tangoTypeConst>
+    inline void __set_write_value_array(Tango::WAttribute &att,
+                                        boost::python::object &seq,
+                                        long x_dim, long y_dim)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+        typedef typename TANGO_const2arraytype(tangoTypeConst) TangoArrayType;
+
+        PyObject *seq_ptr = seq.ptr();
+        long len = (long) PySequence_Size(seq_ptr);
+        twod2oned(len, x_dim, y_dim);
+
+        TangoScalarType *tg_ptr = TangoArrayType::allocbuf(len);
+
+        for (long idx = 0; idx < len; ++idx)
+        {
+            PyObject *elt_ptr = PySequence_GetItem(seq_ptr, idx);
+
+            // The boost extract could be used:
+            // TangoScalarType val = boost::python::extract<TangoScalarType>(elt_ptr);
+            // instead of the code below.
+            // the problem is that extract is considerably slower than our
+            // convert function which only has to deal with the specific tango
+            // data types
+            try
+            {
+                TangoScalarType tg_scalar;
+                from_py<tangoTypeConst>::convert(elt_ptr, tg_scalar);
+                tg_ptr[idx] = tg_scalar;
+                Py_DECREF(elt_ptr);
+            }
+            catch(...)
+            {
+                Py_DECREF(elt_ptr);
+                delete [] tg_ptr;
+                throw;
+            }
+        }
+
+        try
+        {
+            att.set_write_value(tg_ptr, x_dim, y_dim);
+            delete [] tg_ptr;
+        }
+        catch(...)
+        {
+            delete [] tg_ptr;
+            throw;
+        }
+    }
+
+    template<>
+    inline void __set_write_value_array<Tango::DEV_ENCODED>(Tango::WAttribute &att,
+                                                            boost::python::object &seq,
+                                                            long x_dim, long y_dim)
+    {
+        Tango::Except::throw_exception(
+                "PyDs_WrongPythonDataTypeForAttribute",
+                "set_write_value is not supported for DEV_ENCODED attributes.",
+                "set_write_value()");
+    }
+
+    inline void set_write_value(Tango::WAttribute &att, boost::python::object &value)
+    {
+        long type = att.get_data_type();
+        Tango::AttrDataFormat format = att.get_data_format();
+
+        if (format == Tango::SCALAR)
+        {
+            TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(type, __set_write_value_scalar,
+                                              att, value);
+        }
+        else
+        {
+            if (!PySequence_Check(value.ptr()))
+            {
+                TangoSys_OMemStream o;
+                o << "Wrong Python type for attribute " << att.get_name()
+                  << "of type " << Tango::CmdArgTypeName[type]
+                  << ". Expected a sequence." << ends;
+
+                Tango::Except::throw_exception(
+                        "PyDs_WrongPythonDataTypeForAttribute",
+                        o.str(),
+                        "set_value()");
+            }
+            TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(type, __set_write_value_array,
+                                              att, value,
+                                              PySequence_Size(value.ptr()), 0);
+        }
+    }
+
+    inline void set_write_value(Tango::WAttribute &att,
+                                boost::python::object &value,
+                                long x)
+    {
+        long type = att.get_data_type();
+        Tango::AttrDataFormat format = att.get_data_format();
+
+        if (format == Tango::SCALAR)
+        {
+            TangoSys_OMemStream o;
+            o << "Cannot call set_value(data, dim_x) on scalar attribute "
+              << att.get_name() << ". Use set_write_value(data) instead"
+              << ends;
+
+            Tango::Except::throw_exception(
+                    "PyDs_WrongPythonDataTypeForAttribute",
+                    o.str(),
+                    "set_write_value()");
+        }
+        else
+        {
+            if (!PySequence_Check(value.ptr()))
+            {
+                TangoSys_OMemStream o;
+                o << "Wrong Python type for attribute " << att.get_name()
+                  << "of type " << Tango::CmdArgTypeName[type]
+                  << ". Expected a sequence" << ends;
+
+                Tango::Except::throw_exception(
+                        "PyDs_WrongPythonDataTypeForAttribute",
+                        o.str(),
+                        "set_write_value()");
+            }
+            TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(type, __set_write_value_array,
+                                              att, value, x, 0);
+        }
+    }
+
+    inline void set_write_value(Tango::WAttribute &att,
+                                boost::python::object &value,
+                                long x, long y)
+    {
+        long type = att.get_data_type();
+        Tango::AttrDataFormat format = att.get_data_format();
+
+        if (format == Tango::SCALAR)
+        {
+            TangoSys_OMemStream o;
+            o << "Cannot call set_write_value(data, dim_x, dim_y) "
+              << "on scalar attribute " << att.get_name()
+              << ". Use set_write_value(data) instead" << ends;
+
+            Tango::Except::throw_exception(
+                    (const char *)"PyDs_WrongPythonDataTypeForAttribute",
+                    o.str(),
+                    (const char *)"set_write_value()");
+        }
+        else
+        {
+            if (!PySequence_Check(value.ptr()))
+            {
+                TangoSys_OMemStream o;
+                o << "Wrong Python type for attribute " << att.get_name()
+                  << "of type " << Tango::CmdArgTypeName[type]
+                  << ". Expected a sequence" << ends;
+
+                Tango::Except::throw_exception(
+                        (const char *)"PyDs_WrongPythonDataTypeForAttribute",
+                        o.str(),
+                        (const char *)"set_write_value()");
+            }
+            TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(type, __set_write_value_array,
+                                              att, value, x, y);
+        }
+    }
+
+/// @}
+
+    
+/// @name get_write_value
+/// @{ 
+
+    template<long tangoTypeConst>
+    void __get_write_value_pytango3(Tango::WAttribute &att, boost::python::list &seq)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+
+        const TangoScalarType *ptr;
+
+        long length = att.get_write_value_length();
+
+        att.get_write_value(ptr);
+
+        for (long l = 0; l < length; ++l)
+        {
+            seq.append(ptr[l]);
+        }
+    }
+
+    template<>
+    void __get_write_value_pytango3<Tango::DEV_STRING>(Tango::WAttribute &att,
+                                              boost::python::list &seq)
+    {
+        const Tango::ConstDevString *ptr;
+
+        long length = att.get_write_value_length();
+
+        att.get_write_value(ptr);
+
+        for (long l = 0; l < length; ++l)
+        {
+            seq.append(ptr[l]);
+        }
+    }
+
+    inline void get_write_value_pytango3(Tango::WAttribute &att,
+                                boost::python::list &value)
+    {
+        long type = att.get_data_type();
+        TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(type, __get_write_value_pytango3, att, value);
+    }
+
+
+    template<long tangoTypeConst>
+    void __get_write_value_scalar(Tango::WAttribute &att, boost::python::object* obj)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+        
+        TangoScalarType v;
+        att.get_write_value(v);
+        *obj = boost::python::object(v);
+    }
+
+    template<>
+    void __get_write_value_scalar<Tango::DEV_STRING>(Tango::WAttribute &att, boost::python::object* obj)
+    {
+        const Tango::ConstDevString *v = NULL;
+        att.get_write_value(v);
+        *obj = boost::python::object(v[0]);
+    }
+
+    template<long tangoTypeConst>
+    void __get_write_value_array_pytango3(Tango::WAttribute &att, boost::python::object* obj)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+
+        const TangoScalarType * buffer;
+        att.get_write_value(buffer);
+        size_t length = att.get_write_value_length();
+        
+        boost::python::list o;
+        for (size_t n = 0; n < length; ++n)
+            o.append(buffer[n]);
+        *obj = o;
+    }
+
+    template<>
+    void __get_write_value_array_pytango3<Tango::DEV_STRING>(Tango::WAttribute &att, boost::python::object* obj)
+    {
+        const Tango::ConstDevString *ptr;
+        long length = att.get_write_value_length();
+        att.get_write_value(ptr);
+        boost::python::list o;
+        for (long l = 0; l < length; ++l)
+            o.append(ptr[l]);
+    }
+    
+
+    template<long tangoTypeConst>
+    void __get_write_value_array_lists(Tango::WAttribute &att, boost::python::object* obj)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+
+        const TangoScalarType *buffer;
+        att.get_write_value(buffer);
+        size_t dim_x = att.get_w_dim_x();
+        size_t dim_y = att.get_w_dim_y();
+        
+        boost::python::list result;
+
+        if (att.get_data_format() == Tango::SPECTRUM) {
+            for (size_t x=0; x<dim_x; ++x) {
+                result.append(buffer[x]);
+            }
+        } else {
+            for (size_t y=0; y<dim_y; ++y) {
+                boost::python::list row;
+                for (size_t x=0; x<dim_x; ++x) {
+                    row.append(buffer[x + y*dim_x]);
+                }
+                result.append(row);
+            }
+        }
+        *obj = result;
+    }
+
+    template<>
+    void __get_write_value_array_lists<Tango::DEV_STRING>(Tango::WAttribute &att, boost::python::object* obj)
+    {
+        const Tango::ConstDevString* buffer;
+        att.get_write_value(buffer);
+        size_t dim_x = att.get_w_dim_x();
+        size_t dim_y = att.get_w_dim_y();
+        
+        boost::python::list result;
+
+        if (att.get_data_format() == Tango::SPECTRUM) {
+            for (size_t x=0; x<dim_x; ++x) {
+                result.append(buffer[x]);
+            }
+        } else {
+            for (size_t y=0; y<dim_y; ++y) {
+                boost::python::list row;
+                for (size_t x=0; x<dim_x; ++x) {
+                    row.append(buffer[x + y*dim_x]);
+                }
+                result.append(row);
+            }
+        }
+        *obj = result;
+    }
+
+/// @}
+}
+
+#ifndef DISABLE_PYTANGO_NUMPY
+#   include "wattribute_numpy.hpp"
+#endif
+
+
+namespace PyWAttribute
+{
+
+/// @name get_write_value
+/// @{
+    inline boost::python::object get_write_value(Tango::WAttribute &att, PyTango::ExtractAs extract_as)
+    {
+        long type = att.get_data_type();
+        boost::python::object value;
+
+        Tango::AttrDataFormat fmt = att.get_data_format();
+
+        const bool isScalar = fmt == Tango::SCALAR;
+
+        if (isScalar) {
+            TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(type, __get_write_value_scalar, att, &value);
+        } else {
+            switch (extract_as) {
+                case PyTango::ExtractAsPyTango3: {
+                    TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(type,
+                        __get_write_value_array_pytango3, att, &value);
+                    break;
+                }
+                case PyTango::ExtractAsNumpy: {
+#               ifndef DISABLE_PYTANGO_NUMPY
+                    TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(type,
+                        __get_write_value_array_numpy, att, &value);
+                    break;
+#               endif
+                }
+                case PyTango::ExtractAsList: {
+                    TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(type,
+                        __get_write_value_array_lists, att, &value);
+                    break;
+                }
+                default:
+                    Tango::Except::throw_exception(
+                            "PyDs_WrongParameterValue",
+                            "This extract method is not supported by the function.",
+                            "PyWAttribute::get_write_value()");
+            }
+        }
+        return value;
+    }
+
+/// @}
+
+};
+
+
+
+void export_wattribute()
+{
+
+    class_<Tango::WAttribute, bases<Tango::Attribute> >("WAttribute", no_init)
+        .def("get_min_value",
+            (PyObject* (*) (Tango::WAttribute &))
+            &PyWAttribute::get_min_value)
+        .def("get_max_value",
+            (PyObject* (*) (Tango::WAttribute &))
+            &PyWAttribute::get_max_value)
+        .def("set_min_value", &PyWAttribute::set_min_value)
+        .def("set_max_value", &PyWAttribute::set_max_value)
+        .def("is_min_value", &Tango::WAttribute::is_min_value)
+        .def("is_max_value", &Tango::WAttribute::is_max_value)
+        .def("get_write_value_length", &Tango::WAttribute::get_write_value_length)
+        .def("set_write_value",
+            (void (*) (Tango::WAttribute &, boost::python::object &))
+            &PyWAttribute::set_write_value)
+        .def("set_write_value",
+            (void (*) (Tango::WAttribute &, boost::python::object &, long))
+            &PyWAttribute::set_write_value)
+        .def("set_write_value",
+            (void (*) (Tango::WAttribute &, boost::python::object &, long, long))
+            &PyWAttribute::set_write_value)
+
+        // old style get_write_value
+        .def("get_write_value",
+            &PyWAttribute::get_write_value_pytango3,
+            ( arg_("self"), arg_("empty_list")))
+
+        // new style get_write_value
+        .def("get_write_value",
+            &PyWAttribute::get_write_value,
+            ( arg_("self"), arg_("extract_as")=PyTango::ExtractAsNumpy ))
+    ;
+}
diff --git a/src/server/wattribute_numpy.hpp b/src/server/wattribute_numpy.hpp
new file mode 100644
index 0000000..9d63ccd
--- /dev/null
+++ b/src/server/wattribute_numpy.hpp
@@ -0,0 +1,64 @@
+
+// This header file is just some template functions moved apart from
+// wattribute.cpp, and should only be included there.
+
+#pragma once
+
+#include "tango_numpy.h"
+
+namespace PyWAttribute {
+
+    template<long tangoTypeConst>
+    void __get_write_value_array_numpy(Tango::WAttribute &att, boost::python::object* obj)
+    {
+        typedef typename TANGO_const2type(tangoTypeConst) TangoScalarType;
+
+        const TangoScalarType *buffer;
+        att.get_write_value(buffer);
+        size_t length = att.get_write_value_length();
+
+        // Copy buffer in a python raw buffer
+        const char *original_ch_buffer = reinterpret_cast<const char *>(buffer);
+        PyObject* str_guard = PyString_FromStringAndSize(original_ch_buffer, length*sizeof(TangoScalarType));
+
+        if (!str_guard) {
+            throw_error_already_set();
+        }
+
+        // Create a numpy object based on it...
+        static const int typenum = TANGO_const2numpy(tangoTypeConst);
+        npy_intp dims[2];
+        int nd = 1;
+
+        char* ch_buffer = PyString_AsString(str_guard);
+
+        if (att.get_data_format() == Tango::IMAGE) {
+            nd = 2;
+            dims[1] = att.get_w_dim_x();
+            dims[0] = att.get_w_dim_y();
+        } else {
+            nd = 1;
+            dims[0] = att.get_w_dim_x();
+        }
+
+        PyObject* array = PyArray_SimpleNewFromData(nd, dims, typenum, ch_buffer);
+        if (!array) {
+            Py_XDECREF(str_guard);
+            throw_error_already_set();
+        }
+        PyArray_BASE(array) = str_guard;
+        *obj = boost::python::object(boost::python::handle<>(array));
+    }
+    
+    template<>
+    void __get_write_value_array_numpy<Tango::DEV_STRING>(Tango::WAttribute &att, boost::python::object* obj)
+    {
+        __get_write_value_array_lists<Tango::DEV_STRING>(att, obj);
+    }
+
+    template<>
+    void __get_write_value_array_numpy<Tango::DEV_ENCODED>(Tango::WAttribute &att, boost::python::object* obj)
+    {
+        __get_write_value_array_lists<Tango::DEV_STRING>(att, obj);
+    }
+}
diff --git a/src/tango_numpy.h b/src/tango_numpy.h
new file mode 100644
index 0000000..9651514
--- /dev/null
+++ b/src/tango_numpy.h
@@ -0,0 +1,97 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#pragma once
+
+#ifndef DISABLE_PYTANGO_NUMPY
+
+#include <Python.h>
+
+// See "Importing the API" for the why of these weird defines before
+// the inclusion of numpy. They are needed so that you can do import_array
+// in just one file while using numpy in all the project files.
+// http://docs.scipy.org/doc/numpy/reference/c-api.array.html#miscellaneous
+// - {
+#      define PY_ARRAY_UNIQUE_SYMBOL pytango_ARRAY_API
+#      define NO_IMPORT_ARRAY
+#      include <numpy/arrayobject.h>
+// - }
+
+#include <tgutils.h>
+
+/// @name Conversion from a Tango scalar type name to the numpy equivalent name
+/// @{
+
+#   define TANGO_const2numpy(tangoid) tango_name2numpy<tangoid>::value
+
+    template<int N>
+    struct tango_name2numpy
+    {
+        enum { };
+    };
+
+#   define DEF_TANGO2NUMPY(tangoid, numpyid) \
+        template<> \
+        struct tango_name2numpy<tangoid> \
+        { \
+            enum {value = numpyid}; \
+        }
+
+    DEF_TANGO2NUMPY(Tango::DEV_STATE, NPY_UINT32 );
+    DEF_TANGO2NUMPY(Tango::DEV_SHORT, NPY_INT16 );
+    DEF_TANGO2NUMPY(Tango::DEV_LONG, NPY_INT32 );
+    DEF_TANGO2NUMPY(Tango::DEV_DOUBLE, NPY_FLOAT64 );
+    DEF_TANGO2NUMPY(Tango::DEV_FLOAT, NPY_FLOAT32 );
+    DEF_TANGO2NUMPY(Tango::DEV_BOOLEAN, NPY_BOOL );
+    DEF_TANGO2NUMPY(Tango::DEV_USHORT, NPY_UINT16 );
+    DEF_TANGO2NUMPY(Tango::DEV_ULONG, NPY_UINT32 );
+    // Unassigned Tango::DEV_STRING, mapping to NPY_STRING is not copy-free
+    DEF_TANGO2NUMPY(Tango::DEV_UCHAR, NPY_UBYTE );
+    // DEF_TANGO2NUMPY(Tango::DEV_CHAR, NPY_BYTE );
+    //Unassigned: Tango::DEV_ENCODED
+    DEF_TANGO2NUMPY(Tango::DEV_LONG64, NPY_INT64 );
+    DEF_TANGO2NUMPY(Tango::DEV_ULONG64, NPY_UINT64 );
+
+/// @name Conversion from a Tango array type name to the scalar numpy name
+/// For types like DEVVAR_DOUBLEARRAY. This is ended with ARRAY, except
+/// DEVVAR_LONGSTRINGARRAY, DEVVAR_DOUBLESTRINGARRAY and DEVVAR_STRINGARRAY
+/// @{
+
+#   define TANGO_const2scalarnumpy(tangoid) tango_name2scalarnumpy<tangoid>::value
+
+    // We can use TANGO_const2scalarconst which gives us the equivalence
+    // except for DEVVAR_CHARARRAY, that does not have any Scalar type
+    // equivalent.
+    template<int N>
+    struct tango_name2scalarnumpy
+    {
+        enum {value = TANGO_const2numpy(TANGO_const2scalarconst(N)) };
+    };
+    template<>
+    struct tango_name2scalarnumpy<Tango::DEVVAR_CHARARRAY>
+    {
+        enum {value = NPY_UBYTE };
+    };
+/// @}
+
+#endif // #ifndef DISABLE_PYTANGO_NUMPY
diff --git a/src/tgutils.h b/src/tgutils.h
new file mode 100644
index 0000000..4070418
--- /dev/null
+++ b/src/tgutils.h
@@ -0,0 +1,250 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#pragma once
+
+#include <cassert>
+#include <tango.h>
+
+namespace Tango
+{
+    typedef std::vector<DbHistory> DbHistoryList;
+}
+
+template<int N>
+struct tango_name2type
+{
+};
+
+template<typename T>
+struct tango_type2name
+{
+    enum { };
+};
+
+template<int N>
+struct tango_name2arraytype
+{
+};
+
+template<int N>
+struct tango_name2arrayname
+{
+    enum { };
+};
+
+template<int N>
+struct tango_name2scalarname
+{
+    enum { };
+};
+
+#define DEF_TANGO_SCALAR_ARRAY_NAMES(scalarname, arrayname) \
+    template<> \
+    struct tango_name2arrayname<Tango:: scalarname> \
+    { \
+        enum {value = Tango:: arrayname}; \
+    }; \
+    template<> \
+    struct tango_name2scalarname<Tango:: arrayname> \
+    { \
+        enum {value = Tango:: scalarname}; \
+    };
+
+#define DEF_TANGO_NAME2TYPE(tangoname, tangotype) \
+    template<> \
+    struct tango_name2type<Tango:: tangoname> \
+    { \
+        typedef tangotype Type; \
+    }; \
+    template<> \
+    struct tango_type2name<tangotype> \
+    { \
+        enum {value = Tango:: tangoname}; \
+    };
+
+#define DEF_TANGO_NAME2ARRAY(tangoname, tangotype, simple) \
+    template<> \
+    struct tango_name2arraytype<Tango:: tangoname> \
+    { \
+        typedef tangotype Type; \
+        typedef simple ElementsType; \
+    };
+
+#define TSD_SIMPLE__(tangoname, eltangotype, arraytangotype) \
+    DEF_TANGO_NAME2TYPE(tangoname, eltangotype) \
+    DEF_TANGO_NAME2ARRAY(tangoname, arraytangotype, eltangotype)
+
+#define TSD_ARRAY__(tangoname, eltangotype, arraytangotype) \
+    DEF_TANGO_NAME2TYPE(tangoname, arraytangotype) \
+    DEF_TANGO_NAME2ARRAY(tangoname, void, eltangotype)
+
+TSD_SIMPLE__( DEV_SHORT,                Tango::DevShort  ,  Tango::DevVarShortArray   );
+TSD_SIMPLE__( DEV_LONG,                 Tango::DevLong   ,  Tango::DevVarLongArray   );
+TSD_SIMPLE__( DEV_DOUBLE,               Tango::DevDouble ,  Tango::DevVarDoubleArray   );
+TSD_SIMPLE__( DEV_STRING,               Tango::DevString ,  Tango::DevVarStringArray   );
+TSD_SIMPLE__( DEV_FLOAT,                Tango::DevFloat  ,  Tango::DevVarFloatArray   );
+TSD_SIMPLE__( DEV_BOOLEAN,              Tango::DevBoolean,  Tango::DevVarBooleanArray   );
+TSD_SIMPLE__( DEV_USHORT,               Tango::DevUShort ,  Tango::DevVarUShortArray   );
+TSD_SIMPLE__( DEV_ULONG,                Tango::DevULong  ,  Tango::DevVarULongArray   );
+TSD_SIMPLE__( DEV_UCHAR,                Tango::DevUChar  ,  Tango::DevVarUCharArray   );
+TSD_SIMPLE__( DEV_LONG64,               Tango::DevLong64 ,  Tango::DevVarLong64Array   );
+TSD_SIMPLE__( DEV_ULONG64,              Tango::DevULong64,  Tango::DevVarULong64Array   );
+TSD_SIMPLE__( DEV_STATE,                Tango::DevState  ,  Tango::DevVarStateArray   );
+TSD_SIMPLE__( DEV_ENCODED,              Tango::DevEncoded,  Tango::DevVarEncodedArray     );
+
+TSD_SIMPLE__( DEV_VOID,                 void             , void);
+
+TSD_ARRAY__(  DEVVAR_CHARARRAY,         _CORBA_Octet     ,  Tango::DevVarCharArray);
+TSD_ARRAY__(  DEVVAR_SHORTARRAY,        Tango::DevShort  ,  Tango::DevVarShortArray);
+TSD_ARRAY__(  DEVVAR_LONGARRAY,         Tango::DevLong   ,  Tango::DevVarLongArray);
+TSD_ARRAY__(  DEVVAR_FLOATARRAY,        Tango::DevFloat  ,  Tango::DevVarFloatArray);
+TSD_ARRAY__(  DEVVAR_DOUBLEARRAY,       Tango::DevDouble ,  Tango::DevVarDoubleArray);
+TSD_ARRAY__(  DEVVAR_USHORTARRAY,       Tango::DevUShort ,  Tango::DevVarUShortArray);
+TSD_ARRAY__(  DEVVAR_ULONGARRAY,        Tango::DevULong  ,  Tango::DevVarULongArray);
+TSD_ARRAY__(  DEVVAR_STRINGARRAY,       Tango::DevString ,  Tango::DevVarStringArray);
+TSD_ARRAY__(  DEVVAR_LONGSTRINGARRAY,   void             ,  Tango::DevVarLongStringArray);
+TSD_ARRAY__(  DEVVAR_DOUBLESTRINGARRAY, void             ,  Tango::DevVarDoubleStringArray);
+TSD_ARRAY__(  DEVVAR_BOOLEANARRAY,      Tango::DevBoolean,  Tango::DevVarBooleanArray);
+TSD_ARRAY__(  DEVVAR_LONG64ARRAY,       Tango::DevLong64 ,  Tango::DevVarLong64Array);
+TSD_ARRAY__(  DEVVAR_ULONG64ARRAY,      Tango::DevULong64,  Tango::DevVarULong64Array);
+
+ 
+DEF_TANGO_SCALAR_ARRAY_NAMES( DEV_SHORT,   DEVVAR_SHORTARRAY );
+DEF_TANGO_SCALAR_ARRAY_NAMES( DEV_LONG,    DEVVAR_LONGARRAY );
+DEF_TANGO_SCALAR_ARRAY_NAMES( DEV_DOUBLE,  DEVVAR_DOUBLEARRAY );
+DEF_TANGO_SCALAR_ARRAY_NAMES( DEV_STRING,  DEVVAR_STRINGARRAY );
+DEF_TANGO_SCALAR_ARRAY_NAMES( DEV_FLOAT,   DEVVAR_FLOATARRAY );
+DEF_TANGO_SCALAR_ARRAY_NAMES( DEV_BOOLEAN, DEVVAR_BOOLEANARRAY );
+DEF_TANGO_SCALAR_ARRAY_NAMES( DEV_USHORT,  DEVVAR_USHORTARRAY );
+DEF_TANGO_SCALAR_ARRAY_NAMES( DEV_ULONG,   DEVVAR_ULONGARRAY );
+//DEF_TANGO_SCALAR_ARRAY_NAMES( DEV_UCHAR,   DEVVAR_CHARARRAY );
+DEF_TANGO_SCALAR_ARRAY_NAMES( DEV_LONG64,  DEVVAR_LONG64ARRAY );
+DEF_TANGO_SCALAR_ARRAY_NAMES( DEV_ULONG64, DEVVAR_ULONG64ARRAY );
+// DEF_TANGO_SCALAR_ARRAY_NAMES( DEV_STATE,   DEVVAR_STATEARRAY );
+// DEF_TANGO_SCALAR_ARRAY_NAMES( DEV_ENCODED, DEVVAR_ENCODEDARRAY );
+//DEF_TANGO_SCALAR_ARRAY_NAMES( DEV_,        DEVVAR_LONGSTRINGARRAY );
+//DEF_TANGO_SCALAR_ARRAY_NAMES( DEV_,        DEVVAR_DOUBLESTRINGARRAY );
+
+
+
+#define TANGO_type2const(type) tango_type2name<type>::value
+#define TANGO_const2type(name) tango_name2type<name>::Type
+#define TANGO_const2arraytype(name) tango_name2arraytype<name>::Type
+#define TANGO_const2arrayelementstype(name) tango_name2arraytype<name>::ElementsType
+#define TANGO_type2arraytype(type) TANGO_const2arraytype(TANGO_type2const(type))
+#define TANGO_const2string(name) (Tango::CmdArgTypeName[name])
+
+#define TANGO_const2arrayconst(scalarconst) tango_name2arrayname<scalarconst>::value
+#define TANGO_const2scalarconst(arrayconst) tango_name2scalarname<arrayconst>::value
+#define TANGO_const2scalartype TANGO_const2arrayelementstype
+
+
+
+
+
+#define __TANGO_DEPEND_ON_TYPE_AUX(typename_, DOIT) \
+    case Tango:: typename_: { \
+        static const long tangoTypeConst = Tango:: typename_; \
+        DOIT; \
+        break; \
+    }
+
+#define TANGO_DO_ON_ATTRIBUTE_DATA_TYPE(tid, DOIT) if (true) { \
+    switch(tid) { \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_SHORT, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_LONG, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_DOUBLE, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_STRING, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_FLOAT, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_BOOLEAN, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_USHORT, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_ULONG, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_UCHAR, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_LONG64, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_ULONG64, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_STATE, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_ENCODED, DOIT) \
+        default: \
+            assert(false); \
+    } } else (void)0
+
+#define TANGO_CALL_ON_ATTRIBUTE_DATA_TYPE(tid, fn, ...) \
+    TANGO_DO_ON_ATTRIBUTE_DATA_TYPE(tid, fn<tangoTypeConst>(__VA_ARGS__))
+
+/// @todo Not sure about who I choosed to comment out from here...
+#define TANGO_DO_ON_DEVICE_DATA_TYPE(tid, DOIT_SIMPLE, DOIT_ARRAY) if (true) { \
+    switch(tid) { \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_VOID, DOIT_SIMPLE) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_BOOLEAN, DOIT_SIMPLE) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_SHORT, DOIT_SIMPLE) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_LONG, DOIT_SIMPLE) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_FLOAT, DOIT_SIMPLE) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_DOUBLE, DOIT_SIMPLE) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_USHORT, DOIT_SIMPLE) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_ULONG, DOIT_SIMPLE) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_STRING, DOIT_SIMPLE) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEVVAR_CHARARRAY, DOIT_ARRAY) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEVVAR_SHORTARRAY, DOIT_ARRAY) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEVVAR_LONGARRAY, DOIT_ARRAY) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEVVAR_FLOATARRAY, DOIT_ARRAY) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEVVAR_DOUBLEARRAY, DOIT_ARRAY) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEVVAR_USHORTARRAY, DOIT_ARRAY) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEVVAR_ULONGARRAY, DOIT_ARRAY) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEVVAR_STRINGARRAY, DOIT_ARRAY) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEVVAR_LONGSTRINGARRAY, DOIT_ARRAY) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEVVAR_DOUBLESTRINGARRAY, DOIT_ARRAY) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_STATE, DOIT_SIMPLE) \
+/*        __TANGO_DEPEND_ON_TYPE_AUX(CONST_DEV_STRING, DOIT_SIMPLE) */\
+/*        __TANGO_DEPEND_ON_TYPE_AUX(DEVVAR_BOOLEANARRAY, DOIT_ARRAY) */\
+/*        __TANGO_DEPEND_ON_TYPE_AUX(DEV_UCHAR, DOIT_SIMPLE)*/ \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_LONG64, DOIT_SIMPLE) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_ULONG64, DOIT_SIMPLE) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEVVAR_LONG64ARRAY, DOIT_ARRAY) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEVVAR_ULONG64ARRAY, DOIT_ARRAY) \
+/*        __TANGO_DEPEND_ON_TYPE_AUX(DEV_INT, DOIT_SIMPLE) */\
+/*        __TANGO_DEPEND_ON_TYPE_AUX(DEV_ENCODED, DOIT_SIMPLE)*/ \
+        default: \
+            assert(false); \
+    } } else (void)0
+
+#define TANGO_CALL_ON_DEVICE_DATA_TYPE(tid, fn_simple, fn_array, ...) \
+    TANGO_DO_ON_DEVICE_DATA_TYPE(tid, fn_simple<tangoTypeConst>(__VA_ARGS__), fn_array<tangoTypeConst>(__VA_ARGS__))
+
+#define TANGO_DO_ON_NUMERICAL_ATTRIBUTE_DATA_TYPE(tid, DOIT) if (true) { \
+    switch(tid) { \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_SHORT, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_LONG, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_DOUBLE, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_FLOAT, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_USHORT, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_ULONG, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_UCHAR, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_LONG64, DOIT) \
+        __TANGO_DEPEND_ON_TYPE_AUX(DEV_ULONG64, DOIT) \
+        default: \
+            assert(false); \
+    } } else (void)0
+
+#define TANGO_CALL_ON_NUMERICAL_ATTRIBUTE_DATA_TYPE(tid, fn, ...) \
+    TANGO_DO_ON_NUMERICAL_ATTRIBUTE_DATA_TYPE(tid, fn<tangoTypeConst>(__VA_ARGS__))
diff --git a/src/time_val.cpp b/src/time_val.cpp
new file mode 100644
index 0000000..8aa6958
--- /dev/null
+++ b/src/time_val.cpp
@@ -0,0 +1,36 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_time_val()
+{
+    class_<Tango::TimeVal>("TimeVal")
+        .def_readwrite("tv_sec", &Tango::TimeVal::tv_sec)
+        .def_readwrite("tv_usec", &Tango::TimeVal::tv_usec)
+        .def_readwrite("tv_nsec", &Tango::TimeVal::tv_nsec)
+    ;
+}
diff --git a/src/to_py.cpp b/src/to_py.cpp
new file mode 100644
index 0000000..a7e6cc3
--- /dev/null
+++ b/src/to_py.cpp
@@ -0,0 +1,214 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+
+#include "defs.h"
+#include "to_py.h"
+#include "pyutils.h"
+
+using namespace boost::python;
+
+object to_py(const Tango::AttributeAlarm &attr_alarm)
+{
+    PYTANGO_MOD
+    object py_attr_alarm = pytango.attr("AttributeAlarm")();
+    
+    py_attr_alarm.attr("min_alarm") = str(attr_alarm.min_alarm.in());
+    py_attr_alarm.attr("max_alarm") = str(attr_alarm.max_alarm.in());
+    py_attr_alarm.attr("min_warning") = str(attr_alarm.min_warning.in());
+    py_attr_alarm.attr("max_warning") = str(attr_alarm.max_warning.in());
+    py_attr_alarm.attr("delta_t") = str(attr_alarm.delta_t.in());
+    py_attr_alarm.attr("delta_val") = str(attr_alarm.delta_val.in());
+    py_attr_alarm.attr("extensions") = 
+        CORBA_sequence_to_list<Tango::DevVarStringArray>::to_list(attr_alarm.extensions);
+    
+    return py_attr_alarm;
+}
+
+object to_py(const Tango::ChangeEventProp &change_event_prop)
+{
+    PYTANGO_MOD
+    object py_change_event_prop = pytango.attr("ChangeEventProp")();
+    
+    py_change_event_prop.attr("rel_change") = str(change_event_prop.rel_change.in());
+    py_change_event_prop.attr("abs_change") = str(change_event_prop.abs_change.in());
+    py_change_event_prop.attr("extensions") = 
+        CORBA_sequence_to_list<Tango::DevVarStringArray>::to_list(change_event_prop.extensions);
+    
+    return py_change_event_prop;
+}
+
+object to_py(const Tango::PeriodicEventProp &periodic_event_prop)
+{
+    PYTANGO_MOD
+    object py_periodic_event_prop = pytango.attr("PeriodicEventProp")();
+    
+    py_periodic_event_prop.attr("period") = str(periodic_event_prop.period.in());
+    py_periodic_event_prop.attr("extensions") = 
+        CORBA_sequence_to_list<Tango::DevVarStringArray>::to_list(periodic_event_prop.extensions);
+    
+    return py_periodic_event_prop;
+}
+
+object to_py(const Tango::ArchiveEventProp &archive_event_prop)
+{
+    PYTANGO_MOD
+    object py_archive_event_prop = pytango.attr("ArchiveEventProp")();
+    
+    py_archive_event_prop.attr("rel_change") = str(archive_event_prop.rel_change.in());
+    py_archive_event_prop.attr("abs_change") = str(archive_event_prop.abs_change.in());
+    py_archive_event_prop.attr("period") = str(archive_event_prop.period.in());
+    py_archive_event_prop.attr("extensions") = 
+        CORBA_sequence_to_list<Tango::DevVarStringArray>::to_list(archive_event_prop.extensions);
+    
+    return py_archive_event_prop;
+}
+
+object to_py(const Tango::EventProperties &event_props)
+{
+    PYTANGO_MOD
+    object py_event_props = pytango.attr("EventProperties")();
+    
+    py_event_props.attr("ch_event") = to_py(event_props.ch_event);
+    py_event_props.attr("per_event") = to_py(event_props.per_event);
+    py_event_props.attr("arch_event") = to_py(event_props.arch_event);
+    return py_event_props;
+}
+
+object to_py(const Tango::AttributeConfig &attr_conf)
+{
+    PYTANGO_MOD
+    object py_attr_conf = pytango.attr("AttributeConfig")();
+    
+    py_attr_conf.attr("name") = str(attr_conf.name.in());
+    py_attr_conf.attr("writable") = attr_conf.writable;
+    py_attr_conf.attr("data_format") = attr_conf.data_format;
+    py_attr_conf.attr("data_type") = attr_conf.data_type;
+    py_attr_conf.attr("max_dim_x") = attr_conf.max_dim_x;
+    py_attr_conf.attr("max_dim_y") = attr_conf.max_dim_y;
+    py_attr_conf.attr("description") = str(attr_conf.description.in());
+    py_attr_conf.attr("label") = str(attr_conf.label.in());
+    py_attr_conf.attr("unit") = str(attr_conf.unit.in());
+    py_attr_conf.attr("standard_unit") = str(attr_conf.standard_unit.in());
+    py_attr_conf.attr("display_unit") = str(attr_conf.display_unit.in());
+    py_attr_conf.attr("format") = str(attr_conf.format.in());
+    py_attr_conf.attr("min_value") = str(attr_conf.min_value.in());
+    py_attr_conf.attr("max_value") = str(attr_conf.max_value.in());
+    py_attr_conf.attr("min_alarm") = str(attr_conf.min_alarm.in());
+    py_attr_conf.attr("max_alarm") = str(attr_conf.max_alarm.in());
+    py_attr_conf.attr("writable_attr_name") = str(attr_conf.writable_attr_name.in());
+    py_attr_conf.attr("extensions") = 
+        CORBA_sequence_to_list<Tango::DevVarStringArray>::to_list(attr_conf.extensions);
+    
+    return py_attr_conf;
+}
+
+object to_py(const Tango::AttributeConfig_2 &attr_conf)
+{
+    PYTANGO_MOD
+    object py_attr_conf = pytango.attr("AttributeConfig_2")();
+    
+    py_attr_conf.attr("name") = str(attr_conf.name.in());
+    py_attr_conf.attr("writable") = attr_conf.writable;
+    py_attr_conf.attr("data_format") = attr_conf.data_format;
+    py_attr_conf.attr("data_type") = attr_conf.data_type;
+    py_attr_conf.attr("max_dim_x") = attr_conf.max_dim_x;
+    py_attr_conf.attr("max_dim_y") = attr_conf.max_dim_y;
+    py_attr_conf.attr("description") = str(attr_conf.description.in());
+    py_attr_conf.attr("label") = str(attr_conf.label.in());
+    py_attr_conf.attr("unit") = str(attr_conf.unit.in());
+    py_attr_conf.attr("standard_unit") = str(attr_conf.standard_unit.in());
+    py_attr_conf.attr("display_unit") = str(attr_conf.display_unit.in());
+    py_attr_conf.attr("format") = str(attr_conf.format.in());
+    py_attr_conf.attr("min_value") = str(attr_conf.min_value.in());
+    py_attr_conf.attr("max_value") = str(attr_conf.max_value.in());
+    py_attr_conf.attr("min_alarm") = str(attr_conf.min_alarm.in());
+    py_attr_conf.attr("max_alarm") = str(attr_conf.max_alarm.in());
+    py_attr_conf.attr("writable_attr_name") = str(attr_conf.writable_attr_name.in());
+    py_attr_conf.attr("level") = attr_conf.level;
+    py_attr_conf.attr("extensions") = CORBA_sequence_to_list<Tango::DevVarStringArray>::to_list(attr_conf.extensions);
+    
+    return py_attr_conf;
+}
+
+object to_py(const Tango::AttributeConfig_3 &attr_conf)
+{
+    PYTANGO_MOD
+    object py_attr_conf = pytango.attr("AttributeConfig_3")();
+    
+    py_attr_conf.attr("name") = str(attr_conf.name.in());
+    py_attr_conf.attr("writable") = attr_conf.writable;
+    py_attr_conf.attr("data_format") = attr_conf.data_format;
+    py_attr_conf.attr("data_type") = attr_conf.data_type;
+    py_attr_conf.attr("max_dim_x") = attr_conf.max_dim_x;
+    py_attr_conf.attr("max_dim_y") = attr_conf.max_dim_y;
+    py_attr_conf.attr("description") = str(attr_conf.description.in());
+    py_attr_conf.attr("label") = str(attr_conf.label.in());
+    py_attr_conf.attr("unit") = str(attr_conf.unit.in());
+    py_attr_conf.attr("standard_unit") = str(attr_conf.standard_unit.in());
+    py_attr_conf.attr("display_unit") = str(attr_conf.display_unit.in());
+    py_attr_conf.attr("format") = str(attr_conf.format.in());
+    py_attr_conf.attr("min_value") = str(attr_conf.min_value.in());
+    py_attr_conf.attr("max_value") = str(attr_conf.max_value.in());
+    py_attr_conf.attr("writable_attr_name") = str(attr_conf.writable_attr_name.in());
+    py_attr_conf.attr("level") = attr_conf.level;
+    py_attr_conf.attr("att_alarm") = to_py(attr_conf.att_alarm);
+    py_attr_conf.attr("event_prop") = to_py(attr_conf.event_prop);
+    py_attr_conf.attr("extensions") = CORBA_sequence_to_list<Tango::DevVarStringArray>::to_list(attr_conf.extensions);
+    py_attr_conf.attr("sys_extensions") = CORBA_sequence_to_list<Tango::DevVarStringArray>::to_list(attr_conf.sys_extensions);
+    return py_attr_conf;
+}
+
+boost::python::list to_py(const Tango::AttributeConfigList &attr_conf_list)
+{
+    boost::python::list py_attr_conf_list;
+    for(unsigned long index = 0; index < attr_conf_list.length(); ++index)
+    {
+        const Tango::AttributeConfig &attr_conf = attr_conf_list[index];
+        py_attr_conf_list.append(to_py(attr_conf));
+    }
+    return py_attr_conf_list;
+}
+
+boost::python::list to_py(const Tango::AttributeConfigList_2 &attr_conf_list)
+{
+    boost::python::list py_attr_conf_list;
+    for(unsigned long index = 0; index < attr_conf_list.length(); ++index)
+    {
+        const Tango::AttributeConfig_2 &attr_conf = attr_conf_list[index];
+        py_attr_conf_list.append(to_py(attr_conf));
+    }
+    return py_attr_conf_list;
+}
+
+boost::python::list to_py(const Tango::AttributeConfigList_3 &attr_conf_list)
+{
+    boost::python::list py_attr_conf_list;
+    for(unsigned long index = 0; index < attr_conf_list.length(); ++index)
+    {
+        const Tango::AttributeConfig_3 &attr_conf = attr_conf_list[index];
+        py_attr_conf_list.append(to_py(attr_conf));
+    }
+    return py_attr_conf_list;
+}
\ No newline at end of file
diff --git a/src/to_py.h b/src/to_py.h
new file mode 100644
index 0000000..8494751
--- /dev/null
+++ b/src/to_py.h
@@ -0,0 +1,314 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#pragma once
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+#include "defs.h"
+
+template <typename ContainerType>
+struct to_list
+{
+    static inline PyObject* convert(ContainerType const& a)
+    {
+        boost::python::list result;
+        typedef typename ContainerType::const_iterator const_iter;
+        for(const_iter it = a.begin(); it != a.end(); it++)
+        {
+            result.append(boost::python::object(*it));
+        }
+        return boost::python::incref(result.ptr());
+    }
+
+    static const PyTypeObject* get_pytype() { return &PyList_Type; }
+};
+
+template <typename ContainerType>
+struct to_tuple
+{
+    static inline PyObject* convert(ContainerType const& a)
+    {
+        typedef typename ContainerType::const_iterator const_iter;
+        PyObject *t = PyTuple_New(a.size());
+        int32_t i = 0;
+        for(const_iter it = a.begin(); it != a.end(); ++it, ++i)
+        {
+            PyTuple_SetItem(t, i, boost::python::incref(it->ptr()));
+        }
+        return t;
+    }
+
+    static const PyTypeObject* get_pytype() { return &PyTuple_Type; }
+};
+
+template<typename CorbaContainerType>
+struct CORBA_sequence_to_tuple
+{
+    static PyObject* convert(CorbaContainerType const& a)
+    {
+        unsigned long size = a.length();
+        PyObject *t = PyTuple_New(size);
+        for(unsigned long i=0; i < size; ++i)
+        {
+            boost::python::object x(a[i]);
+            PyTuple_SetItem(t, i, boost::python::incref(x.ptr()));
+        }
+        return t;
+    }
+
+    static const PyTypeObject* get_pytype() { return &PyTuple_Type; }
+};
+
+template<>
+struct CORBA_sequence_to_tuple<Tango::DevVarStringArray>
+{
+    static PyObject* convert(Tango::DevVarStringArray const& a)
+    {
+        unsigned long size = a.length();
+        PyObject *t = PyTuple_New(size);
+        for(unsigned long i=0; i < size; ++i)
+        {
+            boost::python::str x(a[i].in());
+            PyTuple_SetItem(t, i, boost::python::incref(x.ptr()));
+        }
+        return t;
+    }
+
+    static const PyTypeObject* get_pytype() { return &PyTuple_Type; }
+};
+
+template<>
+struct CORBA_sequence_to_tuple<Tango::DevVarLongStringArray>
+{
+    static PyObject* convert(Tango::DevVarLongStringArray const& a)
+    {
+        unsigned long lsize = a.lvalue.length();
+        unsigned long ssize = a.svalue.length();
+        PyObject *lt = PyTuple_New(lsize);
+        PyObject *st = PyTuple_New(ssize);
+
+        for(unsigned long i=0; i < lsize; ++i)
+        {
+            boost::python::object x(a.lvalue[i]);
+            PyTuple_SetItem(lt, i, boost::python::incref(x.ptr()));
+        }
+
+        for(unsigned long i=0; i < ssize; ++i)
+        {
+            boost::python::str x(a.svalue[i].in());
+            PyTuple_SetItem(st, i, boost::python::incref(x.ptr()));
+        }
+        PyObject *t = PyTuple_New(2);
+        PyTuple_SetItem(t, 0, lt);
+        PyTuple_SetItem(t, 1, st);
+        return t;
+    }
+
+    static const PyTypeObject* get_pytype() { return &PyTuple_Type; }
+};
+
+template<>
+struct CORBA_sequence_to_tuple<Tango::DevVarDoubleStringArray>
+{
+    static PyObject* convert(Tango::DevVarDoubleStringArray const& a)
+    {
+        unsigned long dsize = a.dvalue.length();
+        unsigned long ssize = a.svalue.length();
+        PyObject *dt = PyTuple_New(dsize);
+        PyObject *st = PyTuple_New(ssize);
+
+        for(unsigned long i=0; i < dsize; ++i)
+        {
+            boost::python::object x(a.dvalue[i]);
+            PyTuple_SetItem(dt, i, boost::python::incref(x.ptr()));
+        }
+
+        for(unsigned long i=0; i < ssize; ++i)
+        {
+            boost::python::str x(a.svalue[i].in());
+            PyTuple_SetItem(st, i, boost::python::incref(x.ptr()));
+        }
+        PyObject *t = PyTuple_New(2);
+        PyTuple_SetItem(t, 0, dt);
+        PyTuple_SetItem(t, 1, st);
+        return t;
+    }
+
+    static const PyTypeObject* get_pytype() { return &PyTuple_Type; }
+};
+
+template<typename CorbaContainerType>
+struct CORBA_sequence_to_list
+{
+    static PyObject* convert(CorbaContainerType const& a)
+    {
+        unsigned long size = a.length();
+        boost::python::list ret;
+        for(unsigned long i=0; i < size; ++i)
+        {
+            ret.append(a[i]);
+        }
+        return boost::python::incref(ret.ptr());
+    }
+
+    static const PyTypeObject* get_pytype() { return &PyList_Type; }
+};
+
+template<>
+struct CORBA_sequence_to_list<Tango::DevVarStringArray>
+{
+    static boost::python::list to_list(Tango::DevVarStringArray const& a)
+    {
+        unsigned long size = a.length();
+        boost::python::list ret;
+        for(unsigned long i=0; i < size; ++i)
+        {
+            ret.append(a[i].in());
+        }
+        return ret;
+    }
+    
+    static PyObject* convert(Tango::DevVarStringArray const& a)
+    {
+        return boost::python::incref(to_list(a).ptr());
+    }
+
+    static const PyTypeObject* get_pytype() { return &PyList_Type; }
+};
+
+template<>
+struct CORBA_sequence_to_list<Tango::DevVarLongStringArray>
+{
+    static PyObject* convert(Tango::DevVarLongStringArray const& a)
+    {
+        unsigned long lsize = a.lvalue.length();
+        unsigned long ssize = a.svalue.length();
+        
+        boost::python::list ret, lt, st;
+        for(unsigned long i=0; i < lsize; ++i)
+        {
+            lt.append(a.lvalue[i]);
+        }
+        
+        for(unsigned long i=0; i < ssize; ++i)
+        {
+            st.append(a.svalue[i]);
+        }
+        
+        ret.append(lt);
+        ret.append(st);
+        
+        return boost::python::incref(ret.ptr());
+    }
+
+    static const PyTypeObject* get_pytype() { return &PyList_Type; }
+};
+
+template<>
+struct CORBA_sequence_to_list <Tango::DevVarDoubleStringArray>
+{
+    static PyObject* convert(Tango::DevVarDoubleStringArray const& a)
+    {
+        unsigned long dsize = a.dvalue.length();
+        unsigned long ssize = a.svalue.length();
+        
+        boost::python::list ret, dt, st;
+        for(unsigned long i=0; i < dsize; ++i)
+        {
+            dt.append(a.dvalue[i]);
+        }
+        
+        for(unsigned long i=0; i < ssize; ++i)
+        {
+            st.append(a.svalue[i]);
+        }
+        
+        ret.append(dt);
+        ret.append(st);
+        
+        return boost::python::incref(ret.ptr());
+    }
+
+    static const PyTypeObject* get_pytype() { return &PyList_Type; }
+};
+
+struct CORBA_String_member_to_str
+{
+    static inline PyObject* convert(CORBA::String_member const& cstr)
+    {
+        return boost::python::incref(boost::python::str(cstr.in()).ptr());
+    }
+
+    static const PyTypeObject* get_pytype() { return &PyString_Type; }
+};
+
+struct CORBA_String_member_to_str2
+{
+    static inline PyObject* convert(_CORBA_String_member const& cstr)
+    {
+        return boost::python::incref(boost::python::str(cstr.in()).ptr());
+    }
+
+    static const PyTypeObject* get_pytype() { return &PyString_Type; }
+};
+
+struct CORBA_String_element_to_str
+{
+    static inline PyObject* convert(_CORBA_String_element const& cstr)
+    {
+        return boost::python::incref(boost::python::str(cstr.in()).ptr());
+    }
+
+    static const PyTypeObject* get_pytype() { return &PyString_Type; }
+};
+
+boost::python::object to_py(const Tango::AttributeAlarm &);
+boost::python::object to_py(const Tango::ChangeEventProp &);
+boost::python::object to_py(const Tango::PeriodicEventProp &);
+boost::python::object to_py(const Tango::ArchiveEventProp &);
+boost::python::object to_py(const Tango::EventProperties &);
+
+boost::python::object to_py(const Tango::AttributeConfig &);
+boost::python::object to_py(const Tango::AttributeConfig_2 &);
+boost::python::object to_py(const Tango::AttributeConfig_3 &);
+
+boost::python::list to_py(const Tango::AttributeConfigList &);
+boost::python::list to_py(const Tango::AttributeConfigList_2 &);
+boost::python::list to_py(const Tango::AttributeConfigList_3 &);
+
+template<class T>
+inline boost::python::object to_py_list(const T *seq)
+{
+    using namespace boost::python;
+    return object(handle<>(CORBA_sequence_to_list<T>::convert(*seq)));
+}
+
+template<class T>
+inline boost::python::object to_py_tuple(const T *seq)
+{
+    using namespace boost::python;
+    return object(handle<>(CORBA_sequence_to_tuple<T>::convert(*seq)));
+}
+
diff --git a/src/to_py_numpy.hpp b/src/to_py_numpy.hpp
new file mode 100644
index 0000000..e7a0358
--- /dev/null
+++ b/src/to_py_numpy.hpp
@@ -0,0 +1,96 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#pragma once
+
+/// @name Array extraction
+/// @{
+
+template <long tangoArrayTypeConst>
+inline boost::python::object to_py_numpy(const typename TANGO_const2type(tangoArrayTypeConst)* tg_array, boost::python::object parent)
+{
+    typedef typename TANGO_const2type(tangoArrayTypeConst) TangoArrayType;
+
+    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.
+    const void *ch_ptr = reinterpret_cast<const void *>(tg_array->get_buffer());
+    int nd = 1;
+    npy_intp dims[1];
+    dims[0]= tg_array->length();
+    PyObject* py_array = PyArray_SimpleNewFromData(nd, dims, typenum, const_cast<void*>(ch_ptr));
+    if (!py_array) {
+        boost::python::throw_error_already_set();
+    }
+
+    // numpy.ndarray() does not own it's memory, so we need to manage it.
+    // We can assign a 'parent' object that will be informed (decref'd)
+    // when the last copy of numpy.ndarray() disappears. That should
+    // actually destroy the memory in its destructor
+    PyObject* guard = parent.ptr();
+    Py_INCREF(guard);
+    PyArray_BASE(py_array) = guard;
+    
+    return boost::python::object(boost::python::handle<>(py_array));
+}
+
+template <>
+inline boost::python::object to_py_numpy<Tango::DEVVAR_STRINGARRAY>(const Tango::DevVarStringArray* tg_array, boost::python::object parent)
+{
+    return to_py_list(tg_array);
+}
+
+template <>
+inline boost::python::object to_py_numpy<Tango::DEVVAR_LONGSTRINGARRAY>(const Tango::DevVarLongStringArray* tg_array, boost::python::object parent)
+{
+    boost::python::list result;
+    
+    result.append(to_py_numpy<Tango::DEVVAR_LONGARRAY>(&tg_array->lvalue, parent));
+    result.append(to_py_numpy<Tango::DEVVAR_STRINGARRAY>(&tg_array->svalue, parent));
+    
+    return result;
+}
+
+template <>
+inline boost::python::object to_py_numpy<Tango::DEVVAR_DOUBLESTRINGARRAY>(const Tango::DevVarDoubleStringArray* tg_array, boost::python::object parent)
+{
+    boost::python::list result;
+    
+    result.append(to_py_numpy<Tango::DEVVAR_DOUBLEARRAY>(&tg_array->dvalue, parent));
+    result.append(to_py_numpy<Tango::DEVVAR_STRINGARRAY>(&tg_array->svalue, parent));
+    
+    return result;
+}
+/// @}
+// ~Array Extraction
+// -----------------------------------------------------------------------
+
diff --git a/src/version.cpp b/src/version.cpp
new file mode 100644
index 0000000..2afd411
--- /dev/null
+++ b/src/version.cpp
@@ -0,0 +1,32 @@
+/*******************************************************************************
+
+   This file is part of PyTango, a python binding for Tango
+
+   http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+
+   (copyleft) CELLS / ALBA Synchrotron, Bellaterra, Spain
+  
+   This is free software; you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+  
+   This software is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Lesser General Public License for more details.
+  
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.
+   
+*******************************************************************************/
+
+#include <boost/python.hpp>
+#include <tango.h>
+
+using namespace boost::python;
+
+void export_version()
+{
+    scope().attr("__tangolib_version__") = TgLibVers;
+}

-- 
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