[pytango] 172/483: api2 initial implementation

Sandor Bodo-Merle sbodomerle-guest at moszumanska.debian.org
Thu Sep 28 19:14:37 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 9d32c90b235a59e3312f5b8e4fd43e63c117da23
Author: tiagocoutinho <tiagocoutinho at 4e9c00fd-8f2e-0410-aa12-93ce3db5e235>
Date:   Mon Oct 22 15:42:03 2012 +0000

    api2 initial implementation
    
    git-svn-id: http://svn.code.sf.net/p/tango-cs/code/bindings/PyTango/trunk@21371 4e9c00fd-8f2e-0410-aa12-93ce3db5e235
---
 PyTango/api2.py      | 185 +++++++++++++++--------
 doc/tep/tep-0001.rst | 405 ++++++++++++++++++++++++++++++++++++---------------
 2 files changed, 410 insertions(+), 180 deletions(-)

diff --git a/PyTango/api2.py b/PyTango/api2.py
index b46a32a..c6ca9b5 100644
--- a/PyTango/api2.py
+++ b/PyTango/api2.py
@@ -21,7 +21,9 @@
 ##
 ################################################################################
 
-"""This module provides a high level device server API. It implements
+""".. _pytango-api2:
+
+This module provides a high level device server API. It implements
 :ref:`TEP1 <pytango-TEP1>`. It exposes an easier API for developing a tango
 device server.
 
@@ -57,11 +59,18 @@ on the low level :mod:`PyTango` server API:
        
 #. read attribute methods can set attribute return value with::
        
-       self.<attr name> = <value>
+       def read_voltage(self):
+           return value
+       
+       # or 
+       
+       def read_voltage(self):
+           self.voltage = value
        
    instead of::
    
-       attr.set_value(<value>)
+       def read_voltage(self, attr):
+           attr.set_value(value)
 
 :class:`Device` works very well in conjuction with:
 
@@ -99,10 +108,10 @@ Here is an example of a PowerSupply device with:
         host = device_property()
         
         def read_voltage(self):
-            self.voltage = 10.0
+            return 10.0
             
         def read_current(self):
-            self.current = 2.5, time(), AttrQuality.ON
+            return 2.5, time(), AttrQuality.ON
         
         @DebugIt()
         def write_current(self):
@@ -207,7 +216,6 @@ from __future__ import print_function
 __all__ = ["DeviceMeta", "Device", "LatestDeviceImpl", "attribute", "command",
            "device_property", "class_property"]
 
-import inspect
 import functools
 import __builtin__
 
@@ -313,7 +321,57 @@ def get_tango_type(dtype):
 
 get_tango_type.__doc__ = __type_doc
 
-def check_tango_device_klass_attribute_method(tango_device_klass, method_name):
+def set_complex_value(attr, value):
+    is_tuple = isinstance(value, tuple)
+    dtype, fmt = attr.get_data_type(), attr.get_data_format()
+    if dtype == CmdArgType.DevEncoded:
+        if is_tuple and len(value) == 4:
+            attr.set_value_date_quality(*value)
+        elif is_tuple and len(value) == 3 and is_non_str_seq(value[0]):
+            attr.set_value_date_quality(value[0][0], value[0][1], *value[1:])
+        else:
+            attr.set_value(*value)
+    else:
+        if is_tuple:
+            if len(value) == 3:
+                if fmt == AttrDataFormat.SCALAR:
+                    attr.set_value_date_quality(*value)
+                elif fmt == AttrDataFormat.SPECTRUM:
+                    if is_seq(value[0]):
+                        attr.set_value_date_quality(*value)
+                    else:
+                        attr.set_value(value)
+                else:
+                    if is_seq(value[0]) and is_seq(value[0][0]):
+                        attr.set_value_date_quality(*value)
+                    else:
+                        attr.set_value(value)
+            else:
+                attr.set_value(value)
+        else:
+            attr.set_value(value)
+
+def check_tango_device_klass_attribute_read_method(tango_device_klass, method_name):
+    """Checks if method given by it's name for the given DeviceImpl class has
+    the correct signature. If a read/write method doesn't have a parameter
+    (the traditional Attribute), then the method is wrapped into another method
+    which has correct parameter definition to make it work.
+    
+    :param tango_device_klass: a DeviceImpl class
+    :type tango_device_klass: class
+    :param method_name: method to be cheched
+    :type attr_data: str"""
+    read_method = getattr(tango_device_klass, method_name)
+
+    @functools.wraps(read_method)
+    def read_attr(self, attr):
+        ret = read_method(self)
+        if not attr.get_value_flag() and ret is not None:
+            set_complex_value(attr, ret)
+        return ret
+    setattr(tango_device_klass, method_name, read_attr)
+
+def check_tango_device_klass_attribute_write_method(tango_device_klass, method_name):
     """Checks if method given by it's name for the given DeviceImpl class has
     the correct signature. If a read/write method doesn't have a parameter
     (the traditional Attribute), then the method is wrapped into another method
@@ -323,24 +381,13 @@ def check_tango_device_klass_attribute_method(tango_device_klass, method_name):
     :type tango_device_klass: class
     :param method_name: method to be cheched
     :type attr_data: str"""
-    f_obj = real_f_obj = getattr(tango_device_klass, method_name)
-
-    # discover the real method because it may be hidden by a tango decorator
-    # like PyTango.DebugIt. Unfortunately we cannot detect other decorators yet
-    while hasattr(real_f_obj, "_wrapped"):
-        real_f_obj = real_f_obj._wrapped
-    argspec = inspect.getargspec(real_f_obj)
-    if argspec.varargs and len(argspec.varargs):
-        return
-    nb = len(argspec.args) - 1
-    if argspec.defaults:
-        nb -= len(argspec.defaults)
-    if nb > 0:
-        return
-    @functools.wraps(f_obj)
-    def f_attr(self, attr):
-        return f_obj(self)
-    setattr(tango_device_klass, method_name, f_attr)
+    write_method = real_f_obj = getattr(tango_device_klass, method_name)
+
+    @functools.wraps(write_method)
+    def write_attr(self, attr):
+        value = attr.get_write_value()
+        return write_method(self, value)
+    setattr(tango_device_klass, method_name, write_attr)
 
 def check_tango_device_klass_attribute_methods(tango_device_klass, attr_data):
     """Checks if the read and write methods have the correct signature. If a 
@@ -352,9 +399,9 @@ def check_tango_device_klass_attribute_methods(tango_device_klass, attr_data):
     :param attr_data: the attribute data information
     :type attr_data: AttrData"""
     if attr_data.attr_write in (AttrWriteType.READ, AttrWriteType.READ_WRITE):
-        check_tango_device_klass_attribute_method(tango_device_klass, attr_data.read_method_name)
+        check_tango_device_klass_attribute_read_method(tango_device_klass, attr_data.read_method_name)
     if attr_data.attr_write in (AttrWriteType.WRITE, AttrWriteType.READ_WRITE):
-        check_tango_device_klass_attribute_method(tango_device_klass, attr_data.write_method_name)
+        check_tango_device_klass_attribute_write_method(tango_device_klass, attr_data.write_method_name)
         
 def create_tango_deviceclass_klass(tango_device_klass, attrs=None):
     klass_name = tango_device_klass.__name__
@@ -375,9 +422,15 @@ def create_tango_deviceclass_klass(tango_device_klass, attrs=None):
     device_property_list = {}
     cmd_list = {}
     devclass_name = klass_name + "Class"
+    
+    def device_class_constructor(self, name):
+        DeviceClass.__init__(self, name)
+        self.set_type(name)
+    
     devclass_attrs = dict(class_property_list=class_property_list,
                           device_property_list=device_property_list,
                           cmd_list=cmd_list, attr_list=attr_list)
+    devclass_attrs['__init__'] = device_class_constructor
     return type(devclass_name, (DeviceClass,), devclass_attrs)
 
 def init_tango_device_klass(tango_device_klass, attrs=None, tango_class_name=None):
@@ -453,35 +506,8 @@ class AttrData2(AttrData):
         return self.get_attribute(obj)
 
     def __set__(self, obj, value):
-        is_tuple = isinstance(value, tuple)
         attr = self.get_attribute(obj)
-        dtype, fmt = attr.get_data_type(), attr.get_data_format()
-        if dtype == CmdArgType.DevEncoded:
-            if is_tuple and len(value) == 4:
-                attr.set_value_date_quality(*value)
-            elif is_tuple and len(value) == 3 and is_non_str_seq(value[0]):
-                attr.set_value_date_quality(value[0][0], value[0][1], *value[1:])
-            else:
-                attr.set_value(*value)
-        else:
-            if is_tuple:
-                if len(value) == 3:
-                    if fmt == AttrDataFormat.SCALAR:
-                        attr.set_value_date_quality(*value)
-                    elif fmt == AttrDataFormat.SPECTRUM:
-                        if is_seq(value[0]):
-                            attr.set_value_date_quality(*value)
-                        else:
-                            attr.set_value(value)
-                    else:
-                        if is_seq(value[0]) and is_seq(value[0][0]):
-                            attr.set_value_date_quality(*value)
-                        else:
-                            attr.set_value(value)
-                else:
-                    attr.set_value(value)
-            else:
-                attr.set_value(value)
+        set_complex_value(attr, value)
     
     def __delete__(self, obj):
         obj.remove_attribute(self.attr_name)
@@ -494,8 +520,9 @@ def attribute(**kwargs):
 
 attribute.__doc__ = """\
 declares a new tango attribute in a :class:`Device`. To be used like the python
-native :obj:`property` function. To declare a scalar, PyTango.DevDouble, read-only
-attribute called *voltage* in a *PowerSupply* :class:`Device` do::
+native :obj:`property` function. For exampke, to declare a scalar, 
+`PyTango.DevDouble`, read-only attribute called *voltage* in a *PowerSupply*
+:class:`Device` do::
 
     class PowerSupply(Device):
         
@@ -541,9 +568,47 @@ It receives multiple keyword arguments.
     :type fwrite: :obj:`str` or :obj:`callable`
     :param is_allowed: is allowed method name or method object [default: 'is_<attr_name>_allowed']
     :type is_allowed: :obj:`str` or :obj:`callable`
-    :param label: attribute label
-    :type label: obj:`str`
-    
+    :param label: attribute label [default: attribute name]
+    :type label: :obj:`str`
+    :param description: attribute description [default: empty string]
+    :type description: :obj:`str`
+    :param unit: attribute unit [default: empty string]
+    :type unit: :obj:`str`
+    :param standard_unit: attribute standard unit [default: empty string]
+    :type standard_unit: :obj:`str`
+    :param display_unit: attribute display unit [default: empty string]
+    :type display_unit: :obj:`str`
+    :param format: attribute representation format [default: '6.2f']
+    :type format: :obj:`str`    
+    :param min_value: attribute minimum allowed value [default: None]
+    :type min_value: :obj:`str`
+    :param max_value: attribute maximum allowed value [default: None]
+    :type max_value: :obj:`str`
+    :param min_alarm: minimum value to trigger attribute alarm [default: None]
+    :type min_alarm: :obj:`str`
+    :param max_alarm: maxmimum value to trigger attribute alarm [default: None]
+    :type max_alarm: :obj:`str`
+    :param min_warning: minimum value to trigger attribute warning [default: None] 
+    :type min_warning: :obj:`str`
+    :param max_warning: attribute maxmimum value to trigger attribute warning [default: None] 
+    :type max_warning: :obj:`str`
+    :param delta_val: attribute 
+    :type delta_val: :obj:`str`
+    :param delta_t: attribute 
+    :type delta_t: :obj:`str`
+    :param abs_change: attribute 
+    :type abs_change: :obj:`str`
+    :param rel_change: attribute 
+    :type rel_change: :obj:`str`
+    :param period: attribute 
+    :type period: :obj:`str`
+    :param archive_abs_change: attribute 
+    :type archive_abs_change: :obj:`str`
+    :param archive_rel_change: attribute 
+    :type archive_rel_change: :obj:`str`
+    :param archive_period: attribute 
+    :type archive_period: :obj:`str`
+
 .. _pytango-api2-datatypes:
 
 .. rubric:: Data type equivalence 
diff --git a/doc/tep/tep-0001.rst b/doc/tep/tep-0001.rst
index 042eaac..c84923f 100644
--- a/doc/tep/tep-0001.rst
+++ b/doc/tep/tep-0001.rst
@@ -12,13 +12,12 @@ TEP 1 - Device Server API Level 2
 ================== ====================================================
  Title:             Device Server API Level 2
  Version:           2.0.0
- Last-Modified:     18-Oct-2012
+ Last-Modified:     22-Oct-2012
  Author:            Tiago Coutinho <tcoutinho at cells.es>
  Status:            Active
  Type:              Standards Track
  Content-Type:      text/x-rst
  Created:           17-Oct-2012
- Post-History:      18-Oct-2012
 ================== ====================================================
 
 Abstract
@@ -31,13 +30,282 @@ Rationale
 
 The code for Tango device servers written in Python often obey a pattern. It
 would be nice if non tango experts could create tango device servers without
-having to code some obscure tango related code. Some of the code which
-is repeated over and over again in almost all python device servers could be
-hidden from the tango developer.
+having to code some obscure tango related code.
+It would also be nice if the tango programming interface would be more pythonic.
+The final goal is to make writting tango device servers as easy as::
+
+    class Motor(Device):
+        __metaclass__ = DeviceMeta
+
+        position = attribute()
+                        
+        def read_position(self):
+            return 2.3
+        
+        @command()        
+        def move(self, position):
+            pass
+
+    if __name__ == "__main__":
+        server_run((Motor,))
+    
 
 Places to simplify
 ===================
 
+After looking at most python device servers one can see some patterns:
+
+At `<Device>` class level:
+    
+    #. <Device> always inherits from latest available DeviceImpl from pogo version
+    #. constructor always does the same:
+        #. calls super constructor
+        #. debug message
+        #. calls init_device
+    
+    #. all methods have debug_stream as first instruction
+    #. init_device does additionaly get_device_properties()
+    #. *read attribute* methods follow the pattern::
+    
+           def read_Attr(self, attr):
+             self.debug_stream()
+             value = get_value_from_hardware()
+             attr.set_value(value)
+    
+    #. *write attribute* methods follow the pattern::
+       
+           def write_Attr(self, attr):
+             self.debug_stream()
+             w_value = attr.get_write_value()
+             apply_value_to_hardware(w_value)
+ 
+At `<Device>Class` class level:
+    
+    #. A <Device>Class class exists for every <DeviceName> class
+    #. The <Device>Class class only contains attributes, commands and
+       properties descriptions (no logic)
+    #. The attr_list description always follows the same (non explicit) pattern
+       (and so does cmd_list, class_property_list, device_property_list)
+    #. the syntax for attr_list, cmd_list, etc is far from understandable 
+     
+At `main()` level:
+
+    #. The main() method always does the same:
+        #. create `Util`
+        #. register tango class
+        #. when registering a python class to become a tango class, 99.9% of times
+           the python class name is the same as the tango class name (example:
+           Motor is registered as tango class "Motor")
+        #. call `server_init()`
+        #. call `server_run()`
+
+High level API
+===============
+
+The goals of the high level API are:
+
+Maintain all features of low-level API available from high-level API
+--------------------------------------------------------------------------------
+
+Everything that was done with the low-level API must also be possible to do
+with the new API.
+
+All tango features should be available by direct usage of the new simplified,
+cleaner high-level API and through direct access to the low-level API.
+    
+Automatic inheritance from the latest** :class:`~PyTango.DeviceImpl` 
+--------------------------------------------------------------------------------
+
+Currently Devices need to inherit from a direct Tango device implementation
+(:class:`~PyTango.DeviceImpl`, or :class:`~PyTango.Device_2Impl`,
+:class:`~PyTango.Device_3Impl`, :class:`~PyTango.Device_4Impl`, etc)
+according to the tango version being used during the development.
+
+In order to keep the code up to date with tango, every time a new Tango IDL
+is released, the code of **every** device server needs to be manually
+updated to ihnerit from the newest tango version.
+
+By inheriting from a new high-level :class:`~PyTango.api2.Device` (which
+itself automatically *decides* from which DeviceImpl version it should
+inherit), the device servers are always up to date with the latest tango
+release without need for manual intervention (see :mod:`PyTango.api2`).
+
+Low-level way::
+
+    class Motor(PyTango.Device_4Impl):
+        pass
+    
+High-level way::
+
+    class Motor(PyTango.api2.Device):
+        pass
+    
+Default implementation of :class:`~PyTango.api2.Device` constructor
+--------------------------------------------------------------------------------
+
+99% of the different device classes which inherit from low level
+:class:`~PyTango.DeviceImpl` only implement `__init__` to call their
+`init_device` (see :mod:`PyTango.api2`).
+
+:class:`~PyTango.api2.Device` already calls init_device.
+
+Low-level way::
+
+    class Motor(PyTango.Device_4Impl):
+        
+        def __init__(self, dev_class, name):
+            PyTango.Device_4Impl.__init__(self, dev_class, name)
+            self.init_device()
+    
+High-level way::
+
+    class Motor(PyTango.api2.Device):
+
+        # Nothing to be done!
+        
+        pass
+
+Default implementation of :meth:`~PyTango.api2.Device.init_device`
+--------------------------------------------------------------------------------
+
+99% of different device classes which inherit from low level
+:class:`~PyTango.DeviceImpl` have an implementation of `init_device` which
+*at least* calls :meth:`~PyTango.DeviceImpl.get_device_properties`
+(see :mod:`PyTango.api2`).
+
+:meth:`~PyTango.api2.Device.init_device` already calls :meth:`~PyTango.api2.Device.get_device_properties`.
+
+Low-level way::
+
+    class Motor(PyTango.Device_4Impl):
+        
+        def init_device(self):
+            self.get_device_properties()
+    
+High-level way::
+
+    class Motor(PyTango.api2.Device):
+        # Nothing to be done!
+        pass
+
+Remove the need to code :class:`~PyTango.DeviceClass`
+--------------------------------------------------------------------------------
+
+99% of different device servers only need to implement their own subclass
+of :class:`~PyTango.DeviceClass` to register the attribute, commands,
+device and class properties by using the corresponding
+:obj:`~PyTango.DeviceClass.attr_list`, :obj:`~PyTango.DeviceClass.cmd_list`,
+:obj:`~PyTango.DeviceClass.device_property_list` and :obj:`~PyTango.DeviceClass.class_property_list`.
+
+With the high-level API we completely remove the need to code the
+:class:`~PyTango.DeviceClass` by registering attribute, commands,
+device and class properties in the :class:`~PyTango.api2.Device` with a more
+pythonic API (see :mod:`PyTango.api2`)
+
+
+#. Hide `<Device>Class` class completely
+#. simplify `main()`
+
+Low-level way::
+
+    class Motor(PyTango.Device_4Impl):
+        
+        def read_Position(self, attr):
+            pass
+
+    class MotorClass(PyTango.DeviceClass):
+
+        class_property_list = { }
+        device_property_list = { }
+        cmd_list = { }
+
+        attr_list = {
+            'Position':
+                [[PyTango.DevDouble,
+                PyTango.SCALAR,
+                PyTango.READ]],
+            }
+
+        def __init__(self, name):
+            PyTango.DeviceClass.__init__(self, name)
+            self.set_type(name)
+
+High-level way::
+
+    class Motor(PyTango.api2.Device):
+        
+        position = PyTango.api2.attribute(dtype=float, )
+
+        def read_position(self):
+            pass
+
+Pythonic read/write attribute
+--------------------------------------------------------------------------------
+
+With the low level API, it feels strange for a non tango programmer to have
+to write::
+
+    def read_Position(self, attr):
+        # ...
+        attr.set_value(new_position)
+
+    def read_Position(self, attr):
+        # ...
+        attr.set_value_date_quality(new_position, time.time(), AttrQuality.CHANGING)
+        
+A more pythonic away would be::
+
+    def read_position(self):
+        # ...
+        self.position = new_position
+
+    def read_position(self):
+        # ...
+        self.position = new_position, time.time(), AttrQuality.CHANGING
+
+Or even::
+
+    def read_position(self):
+        # ...
+        return new_position
+
+    def read_position(self):
+        # ...
+        return new_position, time.time(), AttrQuality.CHANGING
+
+Simplify `main()`
+--------------------------------------------------------------------------------
+
+the typical `main()` method could be greatly simplified.
+initializing tango, registering tango classes, initializing and running the
+server loop and managing errors could all be done with the single function
+call to :func:`~PyTango.server_run`
+
+Low-level way::
+
+    def main():
+        try:
+            py = PyTango.Util(sys.argv)
+            py.add_class(MotorClass,Motor,'Motor')
+
+            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
+        
+High-level way::
+
+    def main():
+        classes = Motor,
+        PyTango.server_run(classes)
+        
+In practice
+===========
+
 Currently, a pogo generated device server code for a Motor having a double
 attribute `position` would look like this::
 
@@ -224,7 +492,8 @@ attribute `position` would look like this::
         main()
 
 
-To make things clear, let's analyse the stripified version of the code instead::
+To make things more fair, let's analyse the stripified version of the code
+instead::
 
     import PyTango
     import sys
@@ -274,7 +543,7 @@ To make things clear, let's analyse the stripified version of the code instead::
             'Position':
                 [[PyTango.DevDouble,
                 PyTango.SCALAR,
-                PyTango.READ_WRITE]],
+                PyTango.READ]],
             }
 
         def __init__(self, name):
@@ -300,138 +569,34 @@ To make things clear, let's analyse the stripified version of the code instead::
     if __name__ == '__main__':
         main()
 
-After looking at most python device servers one can see some patterns:
-
-At `<Device>` class level:
-    
-    #. <Device> always inherits from latest available DeviceImpl from pogo version
-    #. constructor always does the same:
-        #. calls super constructor
-        #. debug message
-        #. calls init_device
-    
-    #. all methods have debug_stream as first instruction
-    #. init_device does additionaly get_device_properties()
- 
-At `<Device>Class` class level:
-    
-    #. A <Device>Class class exists for every <DeviceName> class
-    #. The <Device>Class class only contains attributes, commands and
-       properties descriptions (no logic)
-    #. The attr_list description always follows the same (non explicit) pattern
-       (and so does cmd_list, class_property_list, device_property_list)
-    #. the syntax for attr_list, cmd_list, etc is far from understandable 
-     
-At `main()` level:
-
-    #. The main() method always does the same:
-        #. create `Util`
-        #. register tango class
-        #. `server_init()`
-        #. `server_run()`
-
-
-
-High level API
-==============
-
-The goals of the high level API are:
-    
-    #. Automatically inherit from latest DeviceImpl available from current PyTango installation
-    #. add default implementation for `init_device`: debug_stream(), get_device_properties()
-    #. Hide `<Device>Class` class completely
-    #. simplify `main()`
-
-The final code could look something like this::
+And the equivalent API2 version of the code would be::
 
     #!/usr/bin/env python
 
-    from PyTango import server_run
-    from PyTango.api2 import Device, DeviceMeta, attribute, command, \
-        device_property, class_property
+    from PyTango import DebugIt, server_run
+    from PyTango.api2 import Device, DeviceMeta, attribute
 
 
     class Motor(Device):
         __metaclass__ = DeviceMeta
 
         position = attribute()
-                        
-        def read_position(self, attr):
-            attr.set_value(2.3)
-        
-        @command()        
-        def move(self, position):
-            pass
-        
-    def main():
-        server_run((Motor,))
-
-    if __name__ == "__main__":
-        main()
-
 
-Ok, a pogo generated code could look like this::
+        @DebugIt()
+        def read_position(self):
+            return 1.0
 
-    ##############################################################################
-    # File :        Motor.py
-    # Project :     motor project
-    # Author :     tcoutinho
-    #============================================================================
-    #            This file is generated by POGO
-    #    (Program Obviously used to Generate tango Object)
-    #
-    #        (c) - Software Engineering Group - ESRF
-    ##############################################################################
-
-    import PyTango
-    from PyTango.api2 import Device, DeviceMeta, Attr
-
-    # Add additional import
-    #----- PROTECTED REGION ID(Motor.additionnal_import) ENABLED START -----#
-
-    #----- PROTECTED REGION END -----#	//	Motor.additionnal_import
-
-    class Motor(Device):
-        __metaclass__ = DeviceMeta
-
-        #--------- Add you global variables here --------------------------
-        #----- PROTECTED REGION ID(Motor.global_variables) ENABLED START -----#
-
-        #----- PROTECTED REGION END -----#	//	Motor.global_variables
-
-        def init_device(self):
-            Device.init_device(self)
-            self.attr_Position_read = 0.0
-            #----- PROTECTED REGION ID(Motor.init_device) ENABLED START -----#
-            
-            #----- PROTECTED REGION END -----#	//	Motor.init_device
-        
-        # Motor read/write attribute methods        
-
-        def read_position(self, attr):
-            #----- PROTECTED REGION ID(Motor.Position_read) ENABLED START -----#
-            self.attr_Position_read = 1.0
-            #----- PROTECTED REGION END -----#	//	Motor.Position_read
-            attr.set_value(self.attr_Position_read)
-
-        
-        position = attribute(name='position',
-                             dtype=PyTango.DevDouble,
-                             dformat=PyTango.AttrDataFormat.SCALAR,
-                             fread=read_position)
-        
     def main():
-        classes = Motor,
-        server_run(classes)
+        server_run((Motor,))
 
     if __name__ == "__main__":
         main()
 
-but still is far more inteligable than the original version.
-
 References
 ==========
 
+:mod:`PyTango.api2`
+
 Changes
 =======
 

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