[pytango] 41/483: better dynamic attribute creation
Sandor Bodo-Merle
sbodomerle-guest at moszumanska.debian.org
Thu Sep 28 19:14:22 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 21313b622862e86431a97a8b4d47039d081698ea
Author: tiagocoutinho <tiagocoutinho at 4e9c00fd-8f2e-0410-aa12-93ce3db5e235>
Date: Thu Sep 8 12:50:35 2011 +0000
better dynamic attribute creation
git-svn-id: http://svn.code.sf.net/p/tango-cs/code/bindings/PyTango/trunk@17834 4e9c00fd-8f2e-0410-aa12-93ce3db5e235
---
PyTango/__init__.py | 1 +
PyTango/attr_data.py | 233 +++++++++++++++++++++++++++++++++++++++++++++++
PyTango/device_class.py | 161 ++++----------------------------
PyTango/device_server.py | 38 ++++++--
src/device_proxy.cpp | 1 -
5 files changed, 279 insertions(+), 155 deletions(-)
diff --git a/PyTango/__init__.py b/PyTango/__init__.py
index 4f89022..1c3ee2c 100644
--- a/PyTango/__init__.py
+++ b/PyTango/__init__.py
@@ -58,6 +58,7 @@ __version_description__ = Release.version_description
__doc__ = Release.long_description
import pytango_init
+from attr_data import *
from log4tango import *
from device_server import *
from attribute_proxy import *
diff --git a/PyTango/attr_data.py b/PyTango/attr_data.py
new file mode 100644
index 0000000..d483c4f
--- /dev/null
+++ b/PyTango/attr_data.py
@@ -0,0 +1,233 @@
+################################################################################
+##
+## This file is part of PyTango, a python binding for Tango
+##
+## http://www.tango-controls.org/static/PyTango/latest/doc/html/index.html
+##
+## Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
+##
+## PyTango 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.
+##
+## PyTango 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 PyTango. If not, see <http://www.gnu.org/licenses/>.
+##
+################################################################################
+
+"""
+This is an internal PyTango module.
+"""
+
+__all__ = [ "AttrData" ]
+
+__docformat__ = "restructuredtext"
+
+import operator
+
+from _PyTango import Except, CmdArgType, AttrDataFormat, AttrWriteType, \
+ DispLevel, UserDefaultAttrProp, Attr, SpectrumAttr, ImageAttr
+
+
+class AttrData(object):
+ """A helper class that contains the same information one of the items in
+ DeviceClass.attr_list but in object form"""
+
+ def __init__(self, name, class_name, attr_info=None):
+ self.class_name = class_name
+ self.attr_name = name
+ self.attr_type = CmdArgType.DevVoid
+ self.attr_format = AttrDataFormat.SCALAR
+ self.attr_write = AttrWriteType.READ
+ self.dim_x = 1
+ self.dim_y = 0
+ self.display_level = DispLevel.OPERATOR
+ self.polling_period = -1
+ self.memorized = False
+ self.hw_memorized = False
+ self.read_method_name = "read_%s" % name
+ self.write_method_name = "write_%s" % name
+ self.is_allowed_name = "is_%s_allowed" % name
+ self.attr_class = None
+ self.attr_args = []
+ self.att_prop = None
+ if attr_info is not None:
+ self.from_attr_info(attr_info)
+
+ def __throw_exception(self, msg, meth="create_attribute()"):
+ Except.throw_exception("PyDs_WrongAttributeDefinition", msg, meth)
+
+ 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 from_attr_info(self, attr_info):
+ name = self.class_name
+ attr_name = self.attr_name
+ throw_ex = self.__throw_exception
+ # check for well defined attribute info
+
+ # check parameter
+ if not operator.isSequenceType(attr_info):
+ throw_ex("Wrong data type for value for describing attribute %s in "
+ "class %s\nMust be a sequence with 1 or 2 elements"
+ % (attr_name, name))
+
+ if len(attr_info) < 1 or len(attr_info) > 2:
+ throw_ex("Wrong number of argument for describing attribute %s in "
+ "class %s\nMust be a sequence with 1 or 2 elements"
+ % (attr_name, name))
+
+ 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:
+ throw_ex("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))
+
+ # get data type
+ try:
+ self.attr_type = CmdArgType(attr_info[0])
+ except:
+ throw_ex("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"
+ % (attr_name, name))
+
+ # get format
+ try:
+ self.attr_format = AttrDataFormat(attr_info[1])
+ except:
+ throw_ex("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"
+ % (attr_name, name))
+
+ if self.attr_format == AttrDataFormat.SCALAR:
+ if attr_info_len != 3:
+ throw_ex("Wrong data type in attribute argument for attribute "
+ "%s in class %s\nSequence describing mandatory "
+ "attribute parameters for scalar attribute must have "
+ "3 elements" % (attr_name, name))
+ elif self.attr_format == AttrDataFormat.SPECTRUM:
+ if attr_info_len != 4:
+ throw_ex("Wrong data type in attribute argument for attribute "
+ "%s in class %s\nSequence describing mandatory "
+ "attribute parameters for spectrum attribute must "
+ "have 4 elements" % (attr_name, name))
+ try:
+ self.dim_x = int(attr_info[3])
+ except:
+ throw_ex("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" % (attr_name, name))
+ elif self.attr_format == AttrDataFormat.IMAGE:
+ if attr_info_len != 5:
+ throw_ex("Wrong data type in attribute argument for attribute "
+ "%s in class %s\nSequence describing mandatory "
+ "attribute parameters for image attribute must have "
+ "5 elements" % (attr_name, name))
+ try:
+ self.dim_x = int(attr_info[3])
+ except:
+ throw_ex("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" % (attr_name, name))
+ try:
+ self.dim_y = int(attr_info[4])
+ except:
+ throw_ex("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" % (attr_name, name))
+
+ #get write type
+ try:
+ self.attr_write = AttrWriteType(attr_info[2])
+ except:
+ throw_ex("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" % (attr_name, name))
+ try:
+ self.display_level = DispLevel(extra_info.get("display level",
+ DispLevel.OPERATOR))
+ except:
+ throw_ex("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))
+ try:
+ self.polling_period = int(extra_info.get("polling period", -1))
+ except:
+ throw_ex("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.memorized = extra_info.get("memorized", "false")
+ if self.memorized == "true":
+ self.memorized, self.hw_memorized = True, True
+ elif self.memorized == "true_without_hard_applied":
+ self.memorized = True
+ else:
+ self.memorized = False
+
+ self.attr_class = extra_info.get("klass", self.DftAttrClassMap[self.attr_format])
+ self.attr_args.extend((self.attr_name, self.attr_type, self.attr_write))
+ if not self.attr_format == AttrDataFormat.SCALAR:
+ self.attr_args.append(self.dim_x)
+ if not self.attr_format == AttrDataFormat.SPECTRUM:
+ self.attr_args.append(self.dim_y)
+
+ att_prop = None
+ if extra_info:
+ self.att_prop = self.__create_user_default_attr_prop(attr_name, extra_info)
+
+ def to_attr(self):
+ attr = self.attr_class(*self.attr_args)
+ if self.att_prop is not None:
+ attr.set_default_properties(self.att_prop)
+ attr.set_disp_level(self.display_level)
+ if self.memorized:
+ attr.set_memorized()
+ attr.set_memorized_init(self.hw_memorized)
+ if self.polling_period > 0:
+ attr.set_polling_period(self.polling_period)
+ return attr
+
+ DftAttrClassMap = { AttrDataFormat.SCALAR : Attr,
+ AttrDataFormat.SPECTRUM: SpectrumAttr,
+ AttrDataFormat.IMAGE : ImageAttr }
\ No newline at end of file
diff --git a/PyTango/device_class.py b/PyTango/device_class.py
index e494694..326a801 100644
--- a/PyTango/device_class.py
+++ b/PyTango/device_class.py
@@ -31,12 +31,13 @@ __docformat__ = "restructuredtext"
import types
import operator
+import collections
from _PyTango import Except, DevFailed
from _PyTango import _DeviceClass, Database
from _PyTango import CmdArgType, AttrDataFormat, AttrWriteType, DispLevel
from _PyTango import UserDefaultAttrProp
-
+from _PyTango import Attr, SpectrumAttr, ImageAttr
from pyutil import Util
from utils import seqStr_2_obj, obj_2_str, is_array
@@ -44,6 +45,7 @@ from utils import document_method as __document_method
from globals import get_class, get_class_by_class
from globals import get_constructed_class_by_class
+from attr_data import AttrData
class PropUtil:
"""An internal Property util class"""
@@ -271,6 +273,7 @@ class PropUtil:
"""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
@@ -317,152 +320,20 @@ class DeviceClass(_DeviceClass):
"""for internal usage only"""
for attr_name, attr_info in self.attr_list.iteritems():
- self.__create_attribute(attr_list, attr_name, attr_info)
+ attr_data = AttrData(attr_name, self.get_name(), attr_info)
+ self.__create_attribute(attr_list, attr_data)
- def __create_attribute(self, attr_list, attr_name, attr_info):
+ def __create_attribute(self, attr_list, attr_data):
"""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 = None
- if extra_info:
- 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)
+ self._create_attribute(attr_list, attr_data.attr_name,
+ attr_data.attr_type, attr_data.attr_format,
+ attr_data.attr_write, attr_data.dim_x,
+ attr_data.dim_y, attr_data.display_level,
+ attr_data.polling_period, attr_data.memorized,
+ attr_data.hw_memorized,
+ attr_data.read_method_name,
+ attr_data.write_method_name,
+ attr_data.is_allowed_name, attr_data.att_prop)
def __create_user_default_attr_prop(self, attr_name, extra_info):
"""for internal usage only"""
diff --git a/PyTango/device_server.py b/PyTango/device_server.py
index 4460b9e..0e9bf1a 100644
--- a/PyTango/device_server.py
+++ b/PyTango/device_server.py
@@ -43,6 +43,7 @@ from _PyTango import UserDefaultAttrProp
from utils import document_method as __document_method
from utils import copy_doc
+from attr_data import AttrData
import log4tango
@@ -269,7 +270,7 @@ def __DeviceImpl__get_device_properties(self, ds_class = None):
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_attribute(self, attr, r_meth=None, w_meth=None, is_allo_meth=None) -> Attr
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
@@ -277,33 +278,50 @@ def __DeviceImpl__add_attribute(self, attr, r_meth=None, w_meth=None, is_allo_me
same class created after this attribute addition will also have this attribute.
Parameters :
- attr : (Attr) the new attribute to be added to the list.
+ attr : (Attr or AttrData) 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) the 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
+ w_meth : (callable) the 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
+ Return : (Attr) the newly created attribute.
Throws : DevFailed"""
+
+ attr_data = None
+ if isinstance(attr, AttrData):
+ attr_data = attr
+ attr = attr.to_attr()
+
att_name = attr.get_name()
add_name_in_list = False
if r_meth is not None:
- r_meth_name = 'read_%s' % att_name
+ if attr_data is None:
+ r_meth_name = 'read_%s' % att_name
+ else:
+ r_meth_name = attr_data.read_method_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 attr_data is None:
+ w_meth_name = 'write_%s' % att_name
+ else:
+ w_meth_name = attr_data.write_method_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 attr_data is None:
+ allo_meth_name = 'is_%s_allowed' % att_name
+ else:
+ allo_meth_name = attr_data.is_allowed_name
if not hasattr(self.__class__, allo_meth_name):
- setattr(self.__class__, allo_meth_name,is_allo_meth)
+ setattr(self.__class__, allo_meth_name, is_allo_meth)
add_name_in_list = True
try:
@@ -314,6 +332,8 @@ def __DeviceImpl__add_attribute(self, attr, r_meth=None, w_meth=None, is_allo_me
except:
if add_name_in_list:
self._remove_attr_meth(att_name)
+ raise
+ return attr
def __DeviceImpl__remove_attribute(self, attr_name):
"""
diff --git a/src/device_proxy.cpp b/src/device_proxy.cpp
index d8c6a49..092711f 100644
--- a/src/device_proxy.cpp
+++ b/src/device_proxy.cpp
@@ -127,7 +127,6 @@ namespace PyDeviceProxy
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;
--
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