[pytango] 386/483: Add support for attribute as decorator

Sandor Bodo-Merle sbodomerle-guest at moszumanska.debian.org
Thu Sep 28 19:15:03 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 e62be1a3b00a3397fe9d0ab8bf5371a586783de8
Author: tiagocoutinho <tiagocoutinho at 4e9c00fd-8f2e-0410-aa12-93ce3db5e235>
Date:   Thu May 15 17:24:48 2014 +0000

    Add support for attribute as decorator
    
    git-svn-id: http://svn.code.sf.net/p/tango-cs/code/bindings/PyTango/trunk@25634 4e9c00fd-8f2e-0410-aa12-93ce3db5e235
---
 src/boost/python/server.py | 289 ++++++++++++++++++++++++++++++++-------------
 1 file changed, 208 insertions(+), 81 deletions(-)

diff --git a/src/boost/python/server.py b/src/boost/python/server.py
index a3d9d7f..989a54d 100644
--- a/src/boost/python/server.py
+++ b/src/boost/python/server.py
@@ -152,7 +152,7 @@ def set_complex_value(attr, value):
             attr.set_value(value)
 
 
-def check_tango_device_klass_attribute_read_method(tango_device_klass, method_name):
+def check_tango_device_klass_attribute_read_method(tango_device_klass, attribute):
     """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
@@ -160,9 +160,15 @@ def check_tango_device_klass_attribute_read_method(tango_device_klass, method_na
     
     :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)
+    :param attribute: the attribute data information
+    :type attribute: AttrData"""    
+    read_method = getattr(attribute, "fget", None)
+    if read_method:
+        method_name = "__read_{0}__".format(attribute.attr_name)
+        attribute.read_method_name = method_name
+    else:
+        method_name = attribute.read_method_name
+        read_method = getattr(tango_device_klass, method_name)
 
     @functools.wraps(read_method)
     def read_attr(self, attr):
@@ -173,7 +179,7 @@ def check_tango_device_klass_attribute_read_method(tango_device_klass, method_na
     setattr(tango_device_klass, method_name, read_attr)
 
 
-def check_tango_device_klass_attribute_write_method(tango_device_klass, method_name):
+def check_tango_device_klass_attribute_write_method(tango_device_klass, attribute):
     """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
@@ -181,9 +187,15 @@ def check_tango_device_klass_attribute_write_method(tango_device_klass, method_n
     
     :param tango_device_klass: a DeviceImpl class
     :type tango_device_klass: class
-    :param method_name: method to be cheched
-    :type attr_data: str"""
-    write_method = getattr(tango_device_klass, method_name)
+    :param attribute: the attribute data information
+    :type attribute: AttrData"""
+    write_method = getattr(attribute, "fset", None)
+    if write_method:
+        method_name = "__write_{0}__".format(attribute.attr_name)
+        attribute.write_method_name = method_name
+    else:
+        method_name = attribute.write_method_name
+        write_method = getattr(tango_device_klass, method_name)
 
     @functools.wraps(write_method)
     def write_attr(self, attr):
@@ -192,19 +204,21 @@ def check_tango_device_klass_attribute_write_method(tango_device_klass, method_n
     setattr(tango_device_klass, method_name, write_attr)
 
 
-def check_tango_device_klass_attribute_methods(tango_device_klass, attr_data):
+def check_tango_device_klass_attribute_methods(tango_device_klass, attribute):
     """Checks if the read and write methods have the correct signature. If a 
     read/write method doesn't have a parameter (the traditional Attribute),
     then the method is wrapped into another method to make this work
     
     :param tango_device_klass: a DeviceImpl class
     :type tango_device_klass: class
-    :param 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_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_write_method(tango_device_klass, attr_data.write_method_name)
+    :param attribute: the attribute data information
+    :type attribute: AttrData"""
+    if attribute.attr_write in (AttrWriteType.READ, AttrWriteType.READ_WRITE):
+        check_tango_device_klass_attribute_read_method(tango_device_klass,
+                                                       attribute)
+    if attribute.attr_write in (AttrWriteType.WRITE, AttrWriteType.READ_WRITE):
+        check_tango_device_klass_attribute_write_method(tango_device_klass,
+                                                        attribute)
 
 
 class _DeviceClass(DeviceClass):
@@ -248,13 +262,18 @@ def create_tango_deviceclass_klass(tango_device_klass, attrs=None):
 
     for attr_name, attr_obj in attrs.items():
         if isinstance(attr_obj, attribute):
-            attr_obj._set_name(attr_name)
+            if attr_obj.attr_name is None:
+                attr_obj._set_name(attr_name)
+            else:
+                attr_name = attr_obj.attr_name
             attr_list[attr_name] = attr_obj
             check_tango_device_klass_attribute_methods(tango_device_klass, attr_obj)
         elif isinstance(attr_obj, device_property):
-            device_property_list[attr_name] = [attr_obj.dtype, attr_obj.doc, attr_obj.default_value]
+            device_property_list[attr_name] = [attr_obj.dtype, attr_obj.doc,
+                                               attr_obj.default_value]
         elif isinstance(attr_obj, class_property):
-            class_property_list[attr_name] = [attr_obj.dtype, attr_obj.doc, attr_obj.default_value]
+            class_property_list[attr_name] = [attr_obj.dtype, attr_obj.doc,
+                                              attr_obj.default_value]
         elif inspect.isroutine(attr_obj):
             if hasattr(attr_obj, "__tango_command__"):
                 cmd_name, cmd_info = attr_obj.__tango_command__
@@ -335,68 +354,129 @@ class Device(LatestDeviceImpl):
 
 
 class attribute(AttrData):
-    """declares a new tango attribute in a :class:`Device`. To be used like
-the python native :obj:`property` function. For example, to declare a
-scalar, `PyTango.DevDouble`, read-only attribute called *voltage* in a
-*PowerSupply* :class:`Device` do::
+    '''
+    declares a new tango attribute in a :class:`Device`. To be used like
+    the python native :obj:`property` function. For example, to declare a
+    scalar, `PyTango.DevDouble`, read-only attribute called *voltage* in a
+    *PowerSupply* :class:`Device` do::
 
-    class PowerSupply(Device):
-        __metaclass__ = DeviceMeta
+        class PowerSupply(Device):
+            __metaclass__ = DeviceMeta
         
-        voltage = attribute()
+            voltage = attribute()
+         
+            def read_voltage(self):
+                return 999.999
+
+    The same can be achieved with::
+
+        class PowerSupply(Device):
+            __metaclass__ = DeviceMeta
+
+            @attribute
+            def voltage(self):
+                return 999.999
+
         
-        def read_voltage(self):
-            self.voltage = 1.0
-
-It receives multiple keyword arguments.
-
-===================== ================================ ======================================= =======================================================================================
-parameter              type                                       default value                                 description
-===================== ================================ ======================================= =======================================================================================
-name                   :obj:`str`                       class member name                       alternative attribute name
-dtype                  :obj:`object`                    :obj:`~PyTango.CmdArgType.DevDouble`    data type (see :ref:`Data type equivalence <pytango-hlapi-datatypes>`)
-dformat                :obj:`~PyTango.AttrDataFormat`   :obj:`~PyTango.AttrDataFormat.SCALAR`   data format
-max_dim_x              :obj:`int`                       1                                       maximum size for x dimension (ignored for SCALAR format) 
-max_dim_y              :obj:`int`                       0                                       maximum size for y dimension (ignored for SCALAR and SPECTRUM formats) 
-display_level          :obj:`~PyTango.DispLevel`        :obj:`~PyTango.DisLevel.OPERATOR`       display level
-polling_period         :obj:`int`                       -1                                      polling period
-memorized              :obj:`bool`                      False                                   attribute should or not be memorized
-hw_memorized           :obj:`bool`                      False                                   write method should be called at startup when restoring memorize value (dangerous!)
-access                 :obj:`~PyTango.AttrWriteType`    :obj:`~PyTango.AttrWriteType.READ`      read only/ read write / write only access
-fget (or fread)        :obj:`str` or :obj:`callable`    'read_<attr_name>'                      read method name or method object
-fset (or fwrite)       :obj:`str` or :obj:`callable`    'write_<attr_name>'                     write method name or method object
-is_allowed             :obj:`str` or :obj:`callable`    'is_<attr_name>_allowed'                is allowed method name or method object
-label                  :obj:`str`                       '<attr_name>'                           attribute label
-doc (or description)   :obj:`str`                       ''                                      attribute description
-unit                   :obj:`str`                       ''                                      physical units the attribute value is in
-standard_unit          :obj:`str`                       ''                                      physical standard unit
-display_unit           :obj:`str`                       ''                                      physical display unit (hint for clients)
-format                 :obj:`str`                       '6.2f'                                  attribute representation format
-min_value              :obj:`str`                       None                                    minimum allowed value
-max_value              :obj:`str`                       None                                    maximum allowed value
-min_alarm              :obj:`str`                       None                                    minimum value to trigger attribute alarm
-max_alarm              :obj:`str`                       None                                    maximum value to trigger attribute alarm
-min_warning            :obj:`str`                       None                                    minimum value to trigger attribute warning
-max_warning            :obj:`str`                       None                                    maximum value to trigger attribute warning
-delta_val              :obj:`str`                       None
-delta_t                :obj:`str`                       None
-abs_change             :obj:`str`                       None                                    minimum value change between events that causes event filter to send the event
-rel_change             :obj:`str`                       None                                    minimum relative change between events that causes event filter to send the event (%)
-period                 :obj:`str`                       None
-archive_abs_change     :obj:`str`                       None
-archive_rel_change     :obj:`str`                       None
-archive_period         :obj:`str`                       None
-===================== ================================ ======================================= =======================================================================================
-
-.. note::
-    avoid using *dformat* parameter. If you need a SPECTRUM attribute of say,
-    boolean type, use instead ``dtype=(bool,)``.
-
-"""
-
-    def __init__(self, **kwargs):
+    It receives multiple keyword arguments.
+
+    ===================== ================================ ======================================= =======================================================================================
+    parameter              type                                       default value                                 description
+    ===================== ================================ ======================================= =======================================================================================
+    name                   :obj:`str`                       class member name                       alternative attribute name
+    dtype                  :obj:`object`                    :obj:`~PyTango.CmdArgType.DevDouble`    data type (see :ref:`Data type equivalence <pytango-hlapi-datatypes>`)
+    dformat                :obj:`~PyTango.AttrDataFormat`   :obj:`~PyTango.AttrDataFormat.SCALAR`   data format
+    max_dim_x              :obj:`int`                       1                                       maximum size for x dimension (ignored for SCALAR format) 
+    max_dim_y              :obj:`int`                       0                                       maximum size for y dimension (ignored for SCALAR and SPECTRUM formats) 
+    display_level          :obj:`~PyTango.DispLevel`        :obj:`~PyTango.DisLevel.OPERATOR`       display level
+    polling_period         :obj:`int`                       -1                                      polling period
+    memorized              :obj:`bool`                      False                                   attribute should or not be memorized
+    hw_memorized           :obj:`bool`                      False                                   write method should be called at startup when restoring memorize value (dangerous!)
+    access                 :obj:`~PyTango.AttrWriteType`    :obj:`~PyTango.AttrWriteType.READ`      read only/ read write / write only access
+    fget (or fread)        :obj:`str` or :obj:`callable`    'read_<attr_name>'                      read method name or method object
+    fset (or fwrite)       :obj:`str` or :obj:`callable`    'write_<attr_name>'                     write method name or method object
+    is_allowed             :obj:`str` or :obj:`callable`    'is_<attr_name>_allowed'                is allowed method name or method object
+    label                  :obj:`str`                       '<attr_name>'                           attribute label
+    doc (or description)   :obj:`str`                       ''                                      attribute description
+    unit                   :obj:`str`                       ''                                      physical units the attribute value is in
+    standard_unit          :obj:`str`                       ''                                      physical standard unit
+    display_unit           :obj:`str`                       ''                                      physical display unit (hint for clients)
+    format                 :obj:`str`                       '6.2f'                                  attribute representation format
+    min_value              :obj:`str`                       None                                    minimum allowed value
+    max_value              :obj:`str`                       None                                    maximum allowed value
+    min_alarm              :obj:`str`                       None                                    minimum value to trigger attribute alarm
+    max_alarm              :obj:`str`                       None                                    maximum value to trigger attribute alarm
+    min_warning            :obj:`str`                       None                                    minimum value to trigger attribute warning
+    max_warning            :obj:`str`                       None                                    maximum value to trigger attribute warning
+    delta_val              :obj:`str`                       None
+    delta_t                :obj:`str`                       None
+    abs_change             :obj:`str`                       None                                    minimum value change between events that causes event filter to send the event
+    rel_change             :obj:`str`                       None                                    minimum relative change between events that causes event filter to send the event (%)
+    period                 :obj:`str`                       None
+    archive_abs_change     :obj:`str`                       None
+    archive_rel_change     :obj:`str`                       None
+    archive_period         :obj:`str`                       None
+    ===================== ================================ ======================================= =======================================================================================
+
+    .. note::
+        avoid using *dformat* parameter. If you need a SPECTRUM attribute of say,
+        boolean type, use instead ``dtype=(bool,)``.
+
+    Example of a integer writable attribute with a customized label, unit and
+    description::
+
+        class PowerSupply(Device):
+            __metaclass__ = DeviceMeta
+        
+            current = attribute(label="Current", unit="mA", dtype=int,
+                                access=AttrWriteType.READ_WRITE,
+                                doc="the power supply current")
+
+            def init_device(self):
+                Device.init_device(self)
+                self._current = -1
+    
+            def read_current(self):
+                return self._current
+
+            def write_current(self, current):
+                self._current = current
+
+    The same, but using attribute as a decorator::
+
+        class PowerSupply(Device):
+            __metaclass__ = DeviceMeta
+
+            def init_device(self):
+                Device.init_device(self)
+                self._current = -1
+    
+            @attribute(label="Current", unit="mA", dtype=int)
+            def current(self):
+                """the power supply current"""
+                return 999.999
+
+            @current.write
+            def current(self, current):
+                self._current = current
+
+    In this second format, defining the `write` implies setting the attribute
+    access to READ_WRITE.
+    '''
+
+    def __init__(self, fget=None, **kwargs):
+        self._kwargs = dict(kwargs)
         name = kwargs.pop("name", None)
         class_name = kwargs.pop("class_name", None)
+
+        if fget:
+            if inspect.isroutine(fget):
+                self.fget = fget
+                if 'doc' not in kwargs and 'description' not in kwargs:
+                    kwargs['doc'] = fget.__doc__
+            else:
+                kwargs['fget'] = fget
+        
         super(attribute, self).__init__(name, class_name)
         if 'dtype' in kwargs:
             kwargs['dtype'], kwargs['dformat'] = \
@@ -420,12 +500,24 @@ archive_period         :obj:`str`                       None
     def __delete__(self, obj):
         obj.remove_attribute(self.attr_name)
 
+    def setter(self, fset):
+        """To be used as a decorator. Will define the decorated method as a
+        write attribute method to be called when client writes the attribute"""
+        self.fset = fset
+        if self.attr_write == AttrWriteType.READ:
+            if getattr(self, 'fget', None):
+                self.attr_write = AttrWriteType.READ_WRITE
+            else:
+                self.attr_write = AttrWriteType.WRITE
+        return self
 
-def _attribute(**kwargs):
-    if 'dtype' in kwargs:
-        kwargs['dtype'], kwargs['dformat'] = \
-          get_tango_type_format(kwargs['dtype'], kwargs.get('dformat'))
-    return attribute.from_dict(kwargs)
+    def write(self, fset):
+        """To be used as a decorator. Will define the decorated method as a
+        write attribute method to be called when client writes the attribute"""
+        return self.setter(fset)        
+    
+    def __call__(self, fget):
+        return type(self)(fget=fget, **self._kwargs)
 
 
 def command(f=None, dtype_in=None, dformat_in=None, doc_in="",
@@ -513,10 +605,45 @@ class _property(object):
 
 
 class device_property(_property):
-    pass
+    """
+    Declares a new tango device property in a :class:`Device`. To be used like
+    the python native :obj:`property` function. For example, to declare a
+    scalar, `PyTango.DevString`, device property called *host* in a
+    *PowerSupply* :class:`Device` do::
+
+        from PyTango.server import Device, DeviceMeta
+        from PyTango.server import device_property    
+    
+        class PowerSupply(Device):
+            __metaclass__ = DeviceMeta
+        
+            host = device_property(dtype=str)
 
+    :param dtype: Data type (see :ref:`pytango-data-types`)
+    :param doc: property documentation (optional)
+    :param default_value: default value for the property (optional)
+    """
+    pass
 
 class class_property(_property):
+    """
+    Declares a new tango class property in a :class:`Device`. To be used like
+    the python native :obj:`property` function. For example, to declare a
+    scalar, `PyTango.DevString`, class property called *port* in a *PowerSupply*
+    :class:`Device` do::
+
+        from PyTango.server import Device, DeviceMeta
+        from PyTango.server import class_property    
+    
+        class PowerSupply(Device):
+            __metaclass__ = DeviceMeta
+        
+            port = class_property(dtype=int, default_value=9788)
+
+    :param dtype: Data type (see :ref:`pytango-data-types`)
+    :param doc: property documentation (optional)
+    :param default_value: default value for the property (optional)
+    """    
     pass
 
 

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