summaryrefslogtreecommitdiff
path: root/tango
diff options
context:
space:
mode:
authorBodo-Merle Sandor <sbodomerle@gmail.com>2017-09-28 21:04:57 +0200
committerBodo-Merle Sandor <sbodomerle@gmail.com>2017-09-28 21:04:57 +0200
commitc5e62c5a005860459d6ec6b8d104347003e981e9 (patch)
tree3868b0e69720a97b6fdbcf50a44afc80664bd873 /tango
parent5c7435f4003be654eb511f3a989ad5ac3a092a55 (diff)
New upstream version 9.2.2
Diffstat (limited to 'tango')
-rw-r--r--tango/__init__.py106
-rw-r--r--tango/api_util.py52
-rw-r--r--tango/asyncio.py19
-rw-r--r--tango/asyncio_executor.py101
-rw-r--r--tango/asyncio_tools.py1
-rw-r--r--tango/attr_data.py177
-rw-r--r--tango/attribute_proxy.py136
-rw-r--r--tango/base_types.py210
-rw-r--r--tango/callback.py3
-rw-r--r--tango/client.py20
-rw-r--r--tango/codec.py2
-rw-r--r--tango/connection.py172
-rw-r--r--tango/db.py469
-rw-r--r--tango/device_attribute.py57
-rw-r--r--tango/device_class.py133
-rw-r--r--tango/device_data.py15
-rw-r--r--tango/device_proxy.py434
-rw-r--r--tango/device_server.py138
-rw-r--r--tango/encoded_attribute.py133
-rw-r--r--tango/exception.py60
-rw-r--r--tango/futures.py25
-rw-r--r--tango/futures_executor.py66
-rw-r--r--tango/gevent.py34
-rw-r--r--tango/gevent_executor.py184
-rw-r--r--tango/globals.py23
-rw-r--r--tango/green.py290
-rw-r--r--tango/group.py32
-rw-r--r--tango/group_reply.py13
-rw-r--r--tango/group_reply_list.py10
-rw-r--r--tango/log4tango.py82
-rw-r--r--tango/pipe.py39
-rw-r--r--tango/pipe_data.py39
-rw-r--r--tango/pytango_init.py4
-rw-r--r--tango/pytango_pprint.py87
-rw-r--r--tango/pyutil.py139
-rw-r--r--tango/release.py2
-rw-r--r--tango/server.py381
-rw-r--r--tango/tango_asyncio.py110
-rw-r--r--tango/tango_futures.py47
-rw-r--r--tango/tango_gevent.py120
-rw-r--r--tango/tango_numpy.py27
-rw-r--r--tango/tango_object.py37
-rw-r--r--tango/test_context.py100
-rw-r--r--tango/test_utils.py56
-rw-r--r--tango/time_val.py65
-rw-r--r--tango/utils.py166
46 files changed, 2550 insertions, 2066 deletions
diff --git a/tango/__init__.py b/tango/__init__.py
index 7cc0c94..3e1deb5 100644
--- a/tango/__init__.py
+++ b/tango/__init__.py
@@ -28,7 +28,7 @@ __all__ = [
'AttributeConfig_3', 'AttributeDimension', 'AttributeEventInfo',
'AttributeInfo', 'AttributeInfoEx', 'AttributeInfoList', 'AttributeInfoListEx',
'AttributeList', 'AttributeProxy', 'ChangeEventInfo', 'ChangeEventProp',
- 'Pipe', 'PipeConfig', 'PipeWriteType',
+ 'Pipe', 'PipeConfig', 'PipeWriteType', 'PipeEventData', 'DevIntrChangeEventData',
'CmdArgType', 'CmdDoneEvent', 'CommandInfo', 'CommandInfoList',
'CommunicationFailed', 'Connection', 'ConnectionFailed',
'ConstDevString', 'DServer', 'DataReadyEventData', 'Database', 'DbData',
@@ -49,14 +49,15 @@ __all__ = [
'DeviceUnlocked', 'Device_2Impl', 'Device_3Impl', 'Device_4Impl', 'Device_5Impl',
'DispLevel', 'EncodedAttribute', 'ErrSeverity', 'ErrorIt',
'EventData', 'EventProperties', 'EventSystemFailed', 'EventType',
- 'Except', 'ExtractAs', 'FMT_UNKNOWN', 'FatalIt', 'Group', 'GroupAttrReply',
+ 'Except', 'ExtractAs', 'FMT_UNKNOWN', 'FatalIt', 'GreenMode', 'Group',
+ 'GroupAttrReply',
'GroupAttrReplyList', 'GroupCmdReply', 'GroupCmdReplyList',
'GroupReply', 'GroupReplyList', 'IMAGE', 'ImageAttr', 'InfoIt',
'KeepAliveCmdCode', 'Level', 'LockCmdCode', 'LockerInfo', 'LockerLanguage',
'LogIt', 'LogLevel', 'LogTarget', 'Logger', 'Logging', 'MessBoxType',
'MultiAttribute', 'MultiAttrProp', 'MultiClassAttribute', 'NamedDevFailed',
'NamedDevFailedList', 'NonDbDevice', 'NonSupportedFeature',
- 'NotAllowed', 'NumpyType', 'PeriodicEventInfo', 'PeriodicEventProp',
+ 'NotAllowed', 'PeriodicEventInfo', 'PeriodicEventProp',
'PollCmdCode', 'PollDevice',
'PollObjType', 'READ', 'READ_WITH_WRITE', 'READ_WRITE', 'Release', 'SCALAR',
'SPECTRUM', 'SerialModel', 'SpectrumAttr', 'StdDoubleVector',
@@ -69,19 +70,34 @@ __all__ = [
'class_factory', 'class_list', 'constants', 'constructed_class',
'cpp_class_list', 'delete_class_list', 'get_class', 'get_classes',
'get_constructed_class', 'get_constructed_classes', 'get_cpp_class',
- 'get_cpp_classes', 'is_array_type', 'is_float_type',
- 'is_int_type', 'is_numerical_type', 'is_scalar_type', 'numpy_image',
- 'numpy_spectrum', 'numpy_type', 'obj_2_str', 'raise_asynch_exception',
- 'seqStr_2_obj', 'AutoTangoMonitor', 'AutoTangoAllowThreads',
- 'LatestDeviceImpl']
+ 'get_cpp_classes', 'raise_asynch_exception', 'AutoTangoMonitor',
+ 'AutoTangoAllowThreads', 'LatestDeviceImpl', 'Interceptors',
+ 'get_attribute_proxy', 'requires_tango', 'requires_pytango',
+ 'set_green_mode', 'get_green_mode', 'get_device_proxy',
+ 'is_scalar_type', 'is_array_type', 'is_numerical_type',
+ 'is_int_type', 'is_float_type', 'is_bool_type', 'is_str_type',
+ 'obj_2_str', 'str_2_obj', 'seqStr_2_obj']
__docformat__ = "restructuredtext"
-import os
-import sys
+
+# Prepare windows import
def __prepare_nt():
+ import os
+ import sys
import struct
+
+ if os.name != 'nt':
+ return
+
+ try:
+ from . import _tango # noqa: F401
+ except ImportError:
+ pass
+ else:
+ return
+
PATH = os.environ.get('PATH')
if PATH is None:
os.environ["PATH"] = PATH = ""
@@ -103,7 +119,7 @@ def __prepare_nt():
tango_dll_path = tango_dll_path.lower()
if os.path.exists(tango_dll_path) and \
tango_dll_path not in PATH.lower():
- os.environ['PATH'] += ";" + tango_dll_path
+ os.environ['PATH'] += ";" + tango_dll_path
else:
# Tango C++ could not be found on the system...
# ... use PyTango's private Tango C++ library
@@ -112,15 +128,11 @@ def __prepare_nt():
if os.path.exists(tango_dll_path):
os.environ['PATH'] += ";" + tango_dll_path
-if os.name == 'nt':
- try:
- from . import _tango
- except ImportError as ie:
- # in windows try to find the location for tango
- __prepare_nt()
- from . import _tango
-else:
- from . import _tango
+
+__prepare_nt()
+
+
+# Boost imports
from ._tango import (
AccessControlType, ApiUtil, ArchiveEventInfo,
@@ -129,7 +141,7 @@ from ._tango import (
AttrSerialModel, AttrWriteType, AttrWrittenEvent, Attribute,
AttributeAlarmInfo, AttributeDimension, AttributeEventInfo, AttributeInfo,
AttributeInfoEx, AttributeInfoList, AttributeInfoListEx, AttributeList,
- ChangeEventInfo, CmdArgType, Pipe, PipeWriteType,
+ ChangeEventInfo, CmdArgType, Pipe, PipeWriteType, DevIntrChangeEventData,
CmdDoneEvent, CommandInfo, CommandInfoList, CommunicationFailed,
Connection, ConnectionFailed, ConstDevString, DServer, DataReadyEventData,
Database, DbData, DbDatum, DbDevExportInfo, DbDevExportInfos,
@@ -145,7 +157,7 @@ from ._tango import (
DeviceData, DeviceDataList, DeviceDataHistory, DeviceDataHistoryList,
DeviceImpl, DeviceInfo, DeviceProxy, DeviceUnlocked, Device_2Impl,
Device_3Impl, Device_4Impl, Device_5Impl, DispLevel, EncodedAttribute, ErrSeverity,
- EventData, EventSystemFailed, EventType,
+ EventData, EventSystemFailed, EventType, PipeEventData,
Except, ExtractAs, GreenMode, FMT_UNKNOWN, GroupAttrReply, GroupAttrReplyList,
GroupCmdReply, GroupCmdReplyList, GroupReply, GroupReplyList,
IMAGE, ImageAttr, KeepAliveCmdCode, Level, LockCmdCode, LockerInfo,
@@ -162,8 +174,14 @@ from ._tango import (
raise_asynch_exception, Interceptors,
AutoTangoMonitor, AutoTangoAllowThreads)
+
+# Aliases
+
ArgType = CmdArgType
+
+# Release
+
from .release import Release
__author__ = Release.author_lines
@@ -174,27 +192,45 @@ __version_number__ = Release.version_number
__version_description__ = Release.version_description
__doc__ = Release.long_description
+# Pytango imports
+
from .attr_data import AttrData
-from .log4tango import TangoStream, LogIt, DebugIt, InfoIt, WarnIt, \
- ErrorIt, FatalIt
-from .device_server import ChangeEventProp, PeriodicEventProp, \
- ArchiveEventProp, AttributeAlarm, EventProperties, AttributeConfig, \
- AttributeConfig_2, AttributeConfig_3, MultiAttrProp, LatestDeviceImpl
+
+from .log4tango import (
+ TangoStream, LogIt, DebugIt, InfoIt, WarnIt, ErrorIt, FatalIt)
+
+from .device_server import (
+ ChangeEventProp, PeriodicEventProp, ArchiveEventProp, AttributeAlarm,
+ EventProperties, AttributeConfig, AttributeConfig_2, AttributeConfig_3,
+ MultiAttrProp, LatestDeviceImpl)
+
from .pipe import PipeConfig
+
from .attribute_proxy import AttributeProxy, get_attribute_proxy
+
from .group import Group
+
from .pyutil import Util
+
from .device_class import DeviceClass
-from .globals import 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
-from .utils import is_scalar_type, is_array_type, is_numerical_type, \
- is_int_type, is_float_type, is_bool_type, is_str_type, \
- obj_2_str, str_2_obj, seqStr_2_obj, \
- requires_pytango, requires_tango
+
+from .globals import (
+ 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)
+
+from .utils import (
+ requires_pytango, requires_tango,
+ is_scalar_type, is_array_type, is_numerical_type,
+ is_int_type, is_float_type, is_bool_type, is_str_type,
+ obj_2_str, str_2_obj, seqStr_2_obj)
+
from .green import set_green_mode, get_green_mode
+
from .device_proxy import get_device_proxy
-from .tango_numpy import NumpyType, numpy_type, numpy_spectrum, numpy_image
+
+
+# Pytango initialization
from .pytango_init import init as __init
__init()
diff --git a/tango/api_util.py b/tango/api_util.py
index 3ab9cb7..aaa46dc 100644
--- a/tango/api_util.py
+++ b/tango/api_util.py
@@ -21,23 +21,24 @@ from ._tango import ApiUtil
from .utils import document_method, document_static_method, _get_env_var
+
def __init_api_util():
if not hasattr(ApiUtil, "get_env_var"):
ApiUtil.get_env_var = staticmethod(_get_env_var)
+
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 tango
apiutil = tango.ApiUtil.instance()
-
+
New in PyTango 7.1.3
"""
-
+
document_static_method(ApiUtil, "instance", """
instance() -> ApiUtil
@@ -47,42 +48,42 @@ def __doc_api_util():
Return : (ApiUtil) a reference to the ApiUtil singleton object.
New in PyTango 7.1.3
- """ )
+ """)
document_method(ApiUtil, "pending_asynch_call", """
pending_asynch_call(self, req) -> int
- Return number of asynchronous pending requests (any device).
+ 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
New in PyTango 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.
+ 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.
-
+
New in PyTango 7.1.3
-
+
get_asynch_replies(self) -> None
Fire callback methods for all (any device) asynchronous requests
@@ -96,20 +97,20 @@ def __doc_api_util():
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
+
+ Throws : AsynReplyNotArrived. All other errors are reported using
+ the err and errors fields of the object passed to the
callback methods.
-
+
New in PyTango 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
@@ -118,7 +119,7 @@ def __doc_api_util():
Return : None
New in PyTango 7.1.3
- """ )
+ """)
document_method(ApiUtil, "get_asynch_cb_sub_model", """
get_asynch_cb_sub_model(self) -> cb_sub_model
@@ -129,9 +130,10 @@ def __doc_api_util():
Return : (cb_sub_model) the active asynchronous callback sub-model.
New in PyTango 7.1.3
- """ )
+ """)
+
def api_util_init(doc=True):
__init_api_util()
if doc:
- __doc_api_util() \ No newline at end of file
+ __doc_api_util()
diff --git a/tango/asyncio.py b/tango/asyncio.py
index 8246d02..7e44926 100644
--- a/tango/asyncio.py
+++ b/tango/asyncio.py
@@ -13,16 +13,13 @@
:class:`PyTango.AttributeProxy"""
from __future__ import absolute_import
-
-__all__ = ["DeviceProxy", "AttributeProxy", "check_requirements",
- "get_event_loop"]
-
from functools import partial
-from PyTango import GreenMode
-from PyTango.device_proxy import get_device_proxy
-from PyTango.attribute_proxy import get_attribute_proxy
-from PyTango.tango_asyncio import get_event_loop
+from ._tango import GreenMode
+from .device_proxy import get_device_proxy
+from .attribute_proxy import get_attribute_proxy
+
+__all__ = ["DeviceProxy", "AttributeProxy", "check_requirements"]
def check_requirements():
@@ -47,8 +44,7 @@ def check_requirements():
check_requirements()
DeviceProxy = partial(get_device_proxy,
- green_mode=GreenMode.Asyncio,
- wait=False)
+ green_mode=GreenMode.Asyncio)
DeviceProxy.__doc__ = """
DeviceProxy(self, dev_name, wait=False, timeout=None)
-> DeviceProxy
@@ -94,8 +90,7 @@ DeviceProxy.__doc__ = """
"""
AttributeProxy = partial(get_attribute_proxy,
- green_mode=GreenMode.Asyncio,
- wait=False)
+ green_mode=GreenMode.Asyncio)
AttributeProxy.__doc__ = """
AttributeProxy(self, full_attr_name, wait=False, timeout=False)
-> AttributeProxy
diff --git a/tango/asyncio_executor.py b/tango/asyncio_executor.py
new file mode 100644
index 0000000..5eb0560
--- /dev/null
+++ b/tango/asyncio_executor.py
@@ -0,0 +1,101 @@
+# -----------------------------------------------------------------------------
+# This file is part of PyTango (http://pytango.rtfd.io)
+#
+# Copyright 2006-2012 CELLS / ALBA Synchrotron, Bellaterra, Spain
+# Copyright 2013-2014 European Synchrotron Radiation Facility, Grenoble, France
+#
+# Distributed under the terms of the GNU Lesser General Public License,
+# either version 3 of the License, or (at your option) any later version.
+# See LICENSE.txt for more info.
+# -----------------------------------------------------------------------------
+
+# Future imports
+from __future__ import absolute_import
+
+# Imports
+import functools
+
+try:
+ from threading import get_ident
+except:
+ from threading import _get_ident as get_ident
+
+# Asyncio imports
+try:
+ import asyncio
+except ImportError:
+ import trollius as asyncio
+try:
+ from asyncio import run_coroutine_threadsafe
+except ImportError:
+ from .asyncio_tools import run_coroutine_threadsafe
+
+# Tango imports
+from .green import AbstractExecutor
+
+__all__ = ["AsyncioExecutor", "get_global_executor", "set_global_executor"]
+
+# Asyncio compatibility
+
+ensure_future = getattr(asyncio, 'ensure_future', getattr(asyncio, 'async'))
+
+# Global executor
+
+_EXECUTOR = None
+
+
+def get_global_executor():
+ global _EXECUTOR
+ if _EXECUTOR is None:
+ _EXECUTOR = AsyncioExecutor()
+ return _EXECUTOR
+
+
+def set_global_executor(executor):
+ global _EXECUTOR
+ _EXECUTOR = executor
+
+
+# Asyncio executor
+
+class AsyncioExecutor(AbstractExecutor):
+ """Asyncio tango executor"""
+
+ asynchronous = True
+ default_wait = False
+
+ def __init__(self, loop=None, subexecutor=None):
+ if loop is None:
+ try:
+ loop = asyncio.get_event_loop()
+ except RuntimeError:
+ loop = asyncio.new_event_loop()
+ asyncio.set_event_loop(loop)
+ self.loop = loop
+ self.subexecutor = subexecutor
+
+ def delegate(self, fn, *args, **kwargs):
+ """Return the given operation as an asyncio future."""
+ callback = functools.partial(fn, *args, **kwargs)
+ coro = self.loop.run_in_executor(self.subexecutor, callback)
+ return ensure_future(coro)
+
+ def access(self, accessor, timeout=None):
+ """Return a result from an asyncio future."""
+ if self.loop.is_running():
+ raise RuntimeError("Loop is already running")
+ coro = asyncio.wait_for(accessor, timeout, loop=self.loop)
+ return self.loop.run_until_complete(coro)
+
+ def submit(self, fn, *args, **kwargs):
+ """Submit an operation"""
+ corofn = asyncio.coroutine(lambda: fn(*args, **kwargs))
+ return run_coroutine_threadsafe(corofn(), self.loop)
+
+ def execute(self, fn, *args, **kwargs):
+ """Execute an operation and return the result."""
+ if self.loop._thread_id == get_ident():
+ corofn = asyncio.coroutine(lambda: fn(*args, **kwargs))
+ return corofn()
+ future = self.submit(fn, *args, **kwargs)
+ return future.result()
diff --git a/tango/asyncio_tools.py b/tango/asyncio_tools.py
index 55a0ca0..1992a07 100644
--- a/tango/asyncio_tools.py
+++ b/tango/asyncio_tools.py
@@ -2,6 +2,7 @@
from __future__ import absolute_import
import concurrent.futures
+
try:
import asyncio
except ImportError:
diff --git a/tango/attr_data.py b/tango/attr_data.py
index 8bc6b81..d113c80 100644
--- a/tango/attr_data.py
+++ b/tango/attr_data.py
@@ -16,22 +16,22 @@ This is an internal PyTango module.
from __future__ import with_statement
from __future__ import print_function
-__all__ = [ "AttrData" ]
+__all__ = ["AttrData"]
__docformat__ = "restructuredtext"
import inspect
from ._tango import Except, CmdArgType, AttrDataFormat, AttrWriteType
-from ._tango import DispLevel, UserDefaultAttrProp
-from ._tango import Attr, SpectrumAttr, ImageAttr
+from ._tango import DispLevel, UserDefaultAttrProp, UserDefaultFwdAttrProp
+from ._tango import Attr, SpectrumAttr, ImageAttr, FwdAttr
from .utils import is_non_str_seq, is_pure_str
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
@@ -55,6 +55,7 @@ class AttrData(object):
self.attr_class = None
self.attr_args = []
self.att_prop = None
+ self.forward = False
if attr_info is not None:
self.from_attr_info(attr_info)
@@ -66,61 +67,71 @@ class AttrData(object):
self = cls(name, class_name)
self.build_from_dict(attr_dict)
return self
-
+
def build_from_dict(self, attr_dict):
- self.attr_type = attr_dict.pop('dtype', CmdArgType.DevDouble)
- self.attr_format = attr_dict.pop('dformat', AttrDataFormat.SCALAR)
- self.dim_x = attr_dict.pop('max_dim_x', 1)
- self.dim_y = attr_dict.pop('max_dim_y', 0)
- self.display_level = attr_dict.pop('display_level', DispLevel.OPERATOR)
- self.polling_period = attr_dict.pop('polling_period', -1)
- self.memorized = attr_dict.pop('memorized', False)
- self.hw_memorized = attr_dict.pop('hw_memorized', False)
-
- is_access_explicit = "access" in attr_dict
- if is_access_explicit:
- self.attr_write = attr_dict.pop('access')
- else:
- # access is defined by which methods were defined
- r_explicit = "fread" in attr_dict or "fget" in attr_dict
- w_explicit = "fwrite" in attr_dict or "fset" in attr_dict
- if r_explicit and w_explicit:
- self.attr_write = AttrWriteType.READ_WRITE
- elif r_explicit:
- self.attr_write = AttrWriteType.READ
- elif w_explicit:
- self.attr_write = AttrWriteType.WRITE
+
+ self.forward = attr_dict.pop("forwarded", False)
+ if not self.forward:
+ self.attr_type = attr_dict.pop('dtype', CmdArgType.DevDouble)
+ self.attr_format = attr_dict.pop('dformat', AttrDataFormat.SCALAR)
+ self.dim_x = attr_dict.pop('max_dim_x', 1)
+ self.dim_y = attr_dict.pop('max_dim_y', 0)
+ self.display_level = attr_dict.pop('display_level', DispLevel.OPERATOR)
+ self.polling_period = attr_dict.pop('polling_period', -1)
+ self.memorized = attr_dict.pop('memorized', False)
+ self.hw_memorized = attr_dict.pop('hw_memorized', False)
+
+ is_access_explicit = "access" in attr_dict
+ if is_access_explicit:
+ self.attr_write = attr_dict.pop('access')
else:
- self.attr_write = AttrWriteType.READ
-
- fread = attr_dict.pop('fget', attr_dict.pop('fread', None))
- if fread is not None:
- if is_pure_str(fread):
- self.read_method_name = fread
- elif inspect.isroutine(fread):
- self.read_method_name = fread.__name__
- fwrite = attr_dict.pop('fset', attr_dict.pop('fwrite', None))
- if fwrite is not None:
- if is_pure_str(fwrite):
- self.write_method_name = fwrite
- elif inspect.isroutine(fwrite):
- self.write_method_name = fwrite.__name__
- fisallowed = attr_dict.pop('fisallowed', None)
- if fisallowed is not None:
- if is_pure_str(fisallowed):
- self.is_allowed_name = fisallowed
- elif inspect.isroutine(fisallowed):
- self.is_allowed_name = fisallowed.__name__
- self.attr_class = attr_dict.pop("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)
+ # access is defined by which methods were defined
+ r_explicit = "fread" in attr_dict or "fget" in attr_dict
+ w_explicit = "fwrite" in attr_dict or "fset" in attr_dict
+ if r_explicit and w_explicit:
+ self.attr_write = AttrWriteType.READ_WRITE
+ elif r_explicit:
+ self.attr_write = AttrWriteType.READ
+ elif w_explicit:
+ self.attr_write = AttrWriteType.WRITE
+ else:
+ self.attr_write = AttrWriteType.READ
+
+ fread = attr_dict.pop('fget', attr_dict.pop('fread', None))
+ if fread is not None:
+ if is_pure_str(fread):
+ self.read_method_name = fread
+ elif inspect.isroutine(fread):
+ self.read_method_name = fread.__name__
+ fwrite = attr_dict.pop('fset', attr_dict.pop('fwrite', None))
+ if fwrite is not None:
+ if is_pure_str(fwrite):
+ self.write_method_name = fwrite
+ elif inspect.isroutine(fwrite):
+ self.write_method_name = fwrite.__name__
+ fisallowed = attr_dict.pop('fisallowed', None)
+ if fisallowed is not None:
+ if is_pure_str(fisallowed):
+ self.is_allowed_name = fisallowed
+ elif inspect.isroutine(fisallowed):
+ self.is_allowed_name = fisallowed.__name__
+ self.attr_class = attr_dict.pop("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)
+ else:
+ self.attr_class = FwdAttr
+ self.attr_args = [self.name]
+
if len(attr_dict):
- self.att_prop = self.__create_user_default_attr_prop(attr_dict)
+ if self.forward:
+ self.att_prop = self.__create_user_default_fwdattr_prop(attr_dict)
+ else:
+ self.att_prop = self.__create_user_default_attr_prop(attr_dict)
return self
-
+
def _set_name(self, name):
old_name = self.attr_name
self.attr_name = name
@@ -132,10 +143,16 @@ class AttrData(object):
self.write_method_name = "write_" + name
if self.is_allowed_name is None:
self.is_allowed_name = "is_" + name + "_allowed"
-
+
def __throw_exception(self, msg, meth="create_attribute()"):
Except.throw_exception("PyDs_WrongAttributeDefinition", msg, meth)
+ def __create_user_default_fwdattr_prop(self, extra_info):
+ """for internal usage only"""
+ p = UserDefaultFwdAttrProp()
+ p.set_label(extra_info["label"])
+ return p
+
def __create_user_default_attr_prop(self, extra_info):
"""for internal usage only"""
p = UserDefaultAttrProp()
@@ -143,10 +160,10 @@ class AttrData(object):
doc = extra_info.pop('doc', None)
if doc is not None:
extra_info['description'] = doc
-
+
for k, v in extra_info.items():
k_lower = k.lower()
- method_name = "set_%s" % k_lower.replace(' ','_')
+ method_name = "set_%s" % k_lower.replace(' ', '_')
if hasattr(p, method_name):
method = getattr(p, method_name)
if method_name == 'set_enum_labels':
@@ -155,7 +172,7 @@ class AttrData(object):
method(str(v))
elif k == 'delta_time':
p.set_delta_t(str(v))
- elif not k_lower in ('display level', 'polling period', 'memorized'):
+ elif k_lower not in ('display level', 'polling period', 'memorized'):
msg = "Wrong definition of attribute. " \
"The object extra information '%s' " \
"is not recognized!" % (k,)
@@ -168,27 +185,27 @@ class AttrData(object):
attr_name = self.attr_name
throw_ex = self.__throw_exception
# check for well defined attribute info
-
+
# check parameter
if not is_non_str_seq(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"
+ "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].items():
extra_info[k.lower()] = v
-
+
attr_info = attr_info[0]
-
+
attr_info_len = len(attr_info)
# check parameter
if not is_non_str_seq(attr_info) or \
@@ -196,7 +213,7 @@ class AttrData(object):
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])
@@ -205,7 +222,7 @@ class AttrData(object):
"in class %s\nAttribute data type (first element in first "
"sequence) must be a tango.CmdArgType"
% (attr_name, name))
-
+
# get format
try:
self.attr_format = AttrDataFormat(attr_info[1])
@@ -214,7 +231,7 @@ class AttrData(object):
"in class %s\nAttribute data format (second element in "
"first sequence) must be a tango.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 "
@@ -246,7 +263,7 @@ class AttrData(object):
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))
+ "attribute must be an integer" % (attr_name, name))
try:
self.dim_y = int(attr_info[4])
except:
@@ -254,8 +271,8 @@ class AttrData(object):
"%s in class %s\n5th element in sequence desribing "
"mandatory dim_y attribute parameter for image "
"attribute must be an integer" % (attr_name, name))
-
- #get write type
+
+ # get write type
try:
self.attr_write = AttrWriteType(attr_info[2])
except:
@@ -264,7 +281,7 @@ class AttrData(object):
"element in first sequence) must be a "
"tango.AttrWriteType" % (attr_name, name))
try:
- self.display_level = DispLevel(extra_info.get("display level",
+ self.display_level = DispLevel(extra_info.get("display level",
DispLevel.OPERATOR))
except:
throw_ex("Wrong display level in attribute information for "
@@ -291,10 +308,10 @@ class AttrData(object):
self.memorized = True
else:
self.memorized = False
-
+
if self.attr_type == CmdArgType.DevEnum:
- if not 'enum_labels' in extra_info:
- throw_ex("Missing 'enum_labels' key in attr_list definition "\
+ if 'enum_labels' not in extra_info:
+ throw_ex("Missing 'enum_labels' key in attr_list definition "
"for enum attribute %s in class %s" % (attr_name, name))
self.enum_labels = extra_info["enum_labels"]
@@ -304,12 +321,12 @@ class AttrData(object):
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:
att_prop = self.__create_user_default_attr_prop(extra_info)
self.att_prop = att_prop
-
+
def to_attr(self):
attr = self.attr_class(*self.attr_args)
if self.att_prop is not None:
@@ -321,7 +338,7 @@ class AttrData(object):
if self.polling_period > 0:
attr.set_polling_period(self.polling_period)
return attr
-
- DftAttrClassMap = { AttrDataFormat.SCALAR : Attr,
- AttrDataFormat.SPECTRUM: SpectrumAttr,
- AttrDataFormat.IMAGE : ImageAttr }
+
+ DftAttrClassMap = {AttrDataFormat.SCALAR: Attr,
+ AttrDataFormat.SPECTRUM: SpectrumAttr,
+ AttrDataFormat.IMAGE: ImageAttr}
diff --git a/tango/attribute_proxy.py b/tango/attribute_proxy.py
index d563015..e69c9be 100644
--- a/tango/attribute_proxy.py
+++ b/tango/attribute_proxy.py
@@ -17,20 +17,19 @@ To access these members use directly :mod:`tango` module and NOT
tango.attribute_proxy.
"""
-__all__ = [ "AttributeProxy", "attribute_proxy_init", "get_attribute_proxy" ]
-
-__docformat__ = "restructuredtext"
-
import collections
from ._tango import StdStringVector, DbData, DbDatum, DeviceProxy
from ._tango import __AttributeProxy as _AttributeProxy
from .utils import seq_2_StdStringVector, seq_2_DbData, DbData_2_dict
from .utils import is_pure_str, is_non_str_seq
-from .green import result, submit, get_green_mode, get_wait_default_value
+from .green import green, get_green_mode
from .device_proxy import __init_device_proxy_internals as init_device_proxy
+__all__ = ["AttributeProxy", "attribute_proxy_init", "get_attribute_proxy"]
+
+@green(consume_green_mode=True)
def get_attribute_proxy(*args, **kwargs):
"""
get_attribute_proxy(self, full_attr_name, green_mode=None, wait=True, timeout=True) -> AttributeProxy
@@ -81,14 +80,8 @@ def get_attribute_proxy(*args, **kwargs):
New in PyTango 8.1.0
"""
- # we cannot use the green wrapper because it consumes the green_mode and we
- # want to forward it to the DeviceProxy constructor
- green_mode = kwargs.get('green_mode', get_green_mode())
- wait = kwargs.pop('wait', get_wait_default_value(green_mode))
- timeout = kwargs.pop('timeout', None)
+ return AttributeProxy(*args, **kwargs)
- d = submit(green_mode, AttributeProxy, *args, **kwargs)
- return result(d, green_mode, wait=wait, timeout=timeout)
def __AttributeProxy__get_property(self, propname, value=None):
"""
@@ -141,7 +134,8 @@ def __AttributeProxy__get_property(self, propname, value=None):
if is_pure_str(propname[0]):
new_propname = StdStringVector()
- for i in propname: new_propname.append(i)
+ for i in propname:
+ new_propname.append(i)
new_value = value
if new_value is None:
new_value = DbData()
@@ -149,10 +143,12 @@ def __AttributeProxy__get_property(self, propname, value=None):
return DbData_2_dict(new_value)
elif isinstance(propname[0], DbDatum):
new_value = DbData()
- for i in propname: new_value.append(i)
+ 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
@@ -202,10 +198,12 @@ def __AttributeProxy__put_property(self, value):
new_value.append(db_datum)
value = new_value
else:
- raise TypeError('value must be a tango.DbDatum, tango.DbData,'\
- 'a sequence<DbDatum> or a dictionary')
+ raise TypeError(
+ 'Value must be a tango.DbDatum, tango.DbData, '
+ 'a sequence<DbDatum> or a dictionary')
return self._put_property(value)
+
def __AttributeProxy__delete_property(self, value):
"""
delete_property(self, value) -> None
@@ -242,7 +240,7 @@ def __AttributeProxy__delete_property(self, value):
DevFailed from device (DB_SQLError)
"""
if isinstance(value, DbData) or isinstance(value, StdStringVector) or \
- is_pure_str(value):
+ is_pure_str(value):
new_value = value
elif isinstance(value, DbDatum):
new_value = DbData()
@@ -262,11 +260,13 @@ def __AttributeProxy__delete_property(self, value):
else:
new_value.append(DbDatum(k))
else:
- raise TypeError('value must be a string, tango.DbDatum, '\
- 'tango.DbData, a sequence or a dictionary')
+ raise TypeError(
+ 'Value must be a string, tango.DbDatum, '
+ 'tango.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
@@ -288,6 +288,7 @@ class AttributeProxy(object):
Note: PyTango implementation of AttributeProxy is in part a
python reimplementation of the AttributeProxy found on the C++ API.
"""
+
def __init__(self, *args, **kwds):
green_mode = kwds.pop('green_mode', get_green_mode())
self.__attr_proxy = _AttributeProxy(*args, **kwds)
@@ -326,90 +327,97 @@ class AttributeProxy(object):
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.__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.__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.__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
+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)
+ # 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)
+ 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.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)
+ 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)
+ 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)
+ 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)
+ 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.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.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 attribute_proxy_init(doc=True):
__init_AttributeProxy(doc=doc)
diff --git a/tango/base_types.py b/tango/base_types.py
index 7479162..8a9bd9f 100644
--- a/tango/base_types.py
+++ b/tango/base_types.py
@@ -17,39 +17,42 @@ __all__ = ["base_types_init"]
__docformat__ = "restructuredtext"
-
-from ._tango import (StdStringVector, StdLongVector, StdDoubleVector, \
- CommandInfoList, AttributeInfoList, AttributeInfoListEx, DbData, \
- DbDevInfos, DbDevExportInfos, DbDevImportInfos, DbHistoryList, \
- DeviceDataHistoryList, StdGroupReplyVector, \
- StdGroupCmdReplyVector, StdGroupAttrReplyVector, \
- ArchiveEventInfo, EventData, AttrConfEventData, AttributeAlarmInfo, \
- AttributeDimension, AttributeEventInfo, DeviceAttributeConfig, \
- AttributeInfo, AttributeInfoEx, ChangeEventInfo, PeriodicEventInfo, \
- DevCommandInfo, CommandInfo, DataReadyEventData, DeviceInfo, \
- LockerInfo, PollDevice, TimeVal, AttrWriteType, AttrDataFormat, DispLevel)
+from ._tango import (StdStringVector, StdLongVector, StdDoubleVector,
+ CommandInfoList, AttributeInfoList, AttributeInfoListEx, DbData,
+ DbDevInfos, DbDevExportInfos, DbDevImportInfos, DbHistoryList,
+ DeviceDataHistoryList, StdGroupReplyVector,
+ StdGroupCmdReplyVector, StdGroupAttrReplyVector,
+ ArchiveEventInfo, EventData, AttrConfEventData, AttributeAlarmInfo,
+ AttributeDimension, AttributeEventInfo, DeviceAttributeConfig,
+ AttributeInfo, AttributeInfoEx, ChangeEventInfo, PeriodicEventInfo,
+ DevCommandInfo, CommandInfo, DataReadyEventData, DeviceInfo,
+ LockerInfo, PollDevice, TimeVal, AttrWriteType, AttrDataFormat, DispLevel)
from .utils import document_method, is_integer
from .utils import document_enum as __document_enum
from .utils import seq_2_StdStringVector, StdStringVector_2_seq
+
def __StdVector__add(self, seq):
ret = seq.__class__(self)
ret.extend(seq)
return ret
+
def __StdVector__mul(self, n):
ret = self.__class__()
for _ in range(n):
ret.extend(self)
return ret
+
def __StdVector__imul(self, n):
ret = self.__class__()
for _ in range(n):
ret.extend(self)
return ret
+
def __StdVector__getitem(self, key):
if is_integer(key) or key.step is None:
return self.__original_getitem(key)
@@ -57,7 +60,7 @@ def __StdVector__getitem(self, key):
res = self.__class__()
nb = len(self)
start = key.start or 0
- stop = key.stop or nb
+ stop = key.stop or nb
if start >= nb:
return res
if stop > nb:
@@ -68,6 +71,7 @@ def __StdVector__getitem(self, key):
return res
+
def __fillVectorClass(klass):
klass.__add__ = __StdVector__add
klass.__mul__ = __StdVector__mul
@@ -75,6 +79,7 @@ def __fillVectorClass(klass):
klass.__original_getitem = klass.__getitem__
klass.__getitem__ = __StdVector__getitem
+
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
# DeviceAttributeConfig pickle
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
@@ -82,26 +87,28 @@ def __fillVectorClass(klass):
def __DeviceAttributeConfig__getinitargs__(self):
return ()
+
def __DeviceAttributeConfig__getstate__(self):
- ret = self.name, \
- int(self.writable), \
- int(self.data_format), \
- self.data_type, \
- self.max_dim_x, \
- self.max_dim_y, \
- self.description, \
- self.label, \
- self.unit, \
- self.standard_unit, \
- self.display_unit, \
- self.format, \
- self.min_value, \
- self.max_value, \
- self.min_alarm, \
- self.max_alarm, \
- self.writable_attr_name, \
- StdStringVector_2_seq(self.extensions)
- return ret
+ return (
+ self.name,
+ int(self.writable),
+ int(self.data_format),
+ self.data_type,
+ self.max_dim_x,
+ self.max_dim_y,
+ self.description,
+ self.label,
+ self.unit,
+ self.standard_unit,
+ self.display_unit,
+ self.format,
+ self.min_value,
+ self.max_value,
+ self.min_alarm,
+ self.max_alarm,
+ self.writable_attr_name,
+ StdStringVector_2_seq(self.extensions))
+
def __DeviceAttributeConfig__setstate__(self, state):
self.name = state[0]
@@ -123,6 +130,7 @@ def __DeviceAttributeConfig__setstate__(self, state):
self.writable_attr_name = state[16]
self.extensions = seq_2_StdStringVector(state[17])
+
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
# AttributeInfo pickle
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
@@ -130,15 +138,18 @@ def __DeviceAttributeConfig__setstate__(self, state):
def __AttributeInfo__getinitargs__(self):
return ()
+
def __AttributeInfo__getstate__(self):
ret = list(__DeviceAttributeConfig__getstate__(self))
ret.append(int(self.disp_level))
return tuple(ret)
+
def __AttributeInfo__setstate__(self, state):
__DeviceAttributeConfig__setstate__(self, state)
self.disp_level = DispLevel(state[18])
+
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
# AttributeAlarmInfo pickle
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
@@ -146,14 +157,17 @@ def __AttributeInfo__setstate__(self, state):
def __AttributeAlarmInfo__getinitargs__(self):
return ()
+
def __AttributeAlarmInfo__getstate__(self):
- return self.min_alarm, \
- self.max_alarm, \
- self.min_warning, \
- self.max_warning, \
- self.delta_t, \
- self.delta_val, \
- StdStringVector_2_seq(self.extensions)
+ return (
+ self.min_alarm,
+ self.max_alarm,
+ self.min_warning,
+ self.max_warning,
+ self.delta_t,
+ self.delta_val,
+ StdStringVector_2_seq(self.extensions))
+
def __AttributeAlarmInfo__setstate__(self, state):
self.min_alarm = state[0]
@@ -164,6 +178,7 @@ def __AttributeAlarmInfo__setstate__(self, state):
self.delta_val = state[5]
self.extensions = seq_2_StdStringVector(state[6])
+
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
# ChangeEventInfo pickle
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
@@ -171,16 +186,20 @@ def __AttributeAlarmInfo__setstate__(self, state):
def __ChangeEventInfo__getinitargs__(self):
return ()
+
def __ChangeEventInfo__getstate__(self):
- return self.rel_change, \
- self.abs_change, \
- StdStringVector_2_seq(self.extensions)
+ return (
+ self.rel_change,
+ self.abs_change,
+ StdStringVector_2_seq(self.extensions))
+
def __ChangeEventInfo__setstate__(self, state):
self.rel_change = state[0]
self.abs_change = state[1]
self.extensions = seq_2_StdStringVector(state[2])
+
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
# PeriodicEventInfo pickle
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
@@ -188,14 +207,18 @@ def __ChangeEventInfo__setstate__(self, state):
def __PeriodicEventInfo__getinitargs__(self):
return ()
+
def __PeriodicEventInfo__getstate__(self):
- return self.period, \
- StdStringVector_2_seq(self.extensions)
+ return (
+ self.period,
+ StdStringVector_2_seq(self.extensions))
+
def __PeriodicEventInfo__setstate__(self, state):
self.period = state[0]
self.extensions = seq_2_StdStringVector(state[1])
+
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
# ArchiveEventInfo pickle
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
@@ -203,11 +226,14 @@ def __PeriodicEventInfo__setstate__(self, state):
def __ArchiveEventInfo__getinitargs__(self):
return ()
+
def __ArchiveEventInfo__getstate__(self):
- return self.archive_rel_change, \
- self.archive_abs_change, \
- self.archive_period, \
- StdStringVector_2_seq(self.extensions)
+ return (
+ self.archive_rel_change,
+ self.archive_abs_change,
+ self.archive_period,
+ StdStringVector_2_seq(self.extensions))
+
def __ArchiveEventInfo__setstate__(self, state):
self.archive_rel_change = state[0]
@@ -215,6 +241,7 @@ def __ArchiveEventInfo__setstate__(self, state):
self.archive_period = state[2]
self.extensions = seq_2_StdStringVector(state[3])
+
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
# AttributeEventInfo pickle
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
@@ -222,16 +249,20 @@ def __ArchiveEventInfo__setstate__(self, state):
def __AttributeEventInfo__getinitargs__(self):
return ()
+
def __AttributeEventInfo__getstate__(self):
- return self.ch_event, \
- self.per_event, \
- self.arch_event
+ return (
+ self.ch_event,
+ self.per_event,
+ self.arch_event)
+
def __AttributeEventInfo__setstate__(self, state):
self.ch_event = state[0]
self.per_event = state[1]
self.arch_event = state[2]
+
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
# AttributeInfoEx pickle
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
@@ -239,6 +270,7 @@ def __AttributeEventInfo__setstate__(self, state):
def __AttributeInfoEx__getinitargs__(self):
return ()
+
def __AttributeInfoEx__getstate__(self):
ret = list(__AttributeInfo__getstate__(self))
ret.append(self.alarms)
@@ -246,19 +278,21 @@ def __AttributeInfoEx__getstate__(self):
ret.append(StdStringVector_2_seq(self.sys_extensions))
return tuple(ret)
+
def __AttributeInfoEx__setstate__(self, state):
__AttributeInfo__setstate__(self, state)
self.alarms = state[19]
self.events = state[20]
self.sys_extensions = seq_2_StdStringVector(state[21])
-def __init_base_types():
- v_klasses = (StdStringVector,StdLongVector,StdDoubleVector,CommandInfoList, \
- AttributeInfoList,AttributeInfoListEx,DbData,DbDevInfos, \
- DbDevExportInfos,DbDevImportInfos,DbHistoryList, \
- DeviceDataHistoryList, StdGroupReplyVector, \
- StdGroupCmdReplyVector, StdGroupAttrReplyVector)
+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)
@@ -297,7 +331,6 @@ def __init_base_types():
def __doc_base_types():
-
def document_enum(enum_name, desc):
import tango
__document_enum(tango, enum_name, desc)
@@ -323,7 +356,7 @@ def __doc_base_types():
- String : The data will be stored 'as is', the binary data
as it comes from TangoC++ in 'value'.
- Nothing : The value will not be extracted from DeviceAttribute
- """ )
+ """)
document_enum("CmdArgType", """
An enumeration representing the command argument type.
@@ -359,7 +392,7 @@ def __doc_base_types():
- DevEncoded
- DevEnum
- DevPipeBlob
- """ )
+ """)
document_enum("LockerLanguage", """
An enumeration representing the programming language in which the
@@ -369,7 +402,7 @@ def __doc_base_types():
- JAVA : Java language
New in PyTango 7.0.0
- """ )
+ """)
document_enum("MessBoxType", """
An enumeration representing the MessBoxType
@@ -378,7 +411,7 @@ def __doc_base_types():
- INFO
New in PyTango 7.0.0
- """ )
+ """)
document_enum("PollObjType", """
An enumeration representing the PollObjType
@@ -389,7 +422,7 @@ def __doc_base_types():
- STORE_SUBDEV
New in PyTango 7.0.0
- """ )
+ """)
document_enum("PollCmdCode", """
An enumeration representing the PollCmdCode
@@ -406,7 +439,7 @@ def __doc_base_types():
- POLL_REM_HEARTBEAT
New in PyTango 7.0.0
- """ )
+ """)
document_enum("SerialModel", """
An enumeration representing the type of serialization performed by the device server
@@ -415,14 +448,14 @@ def __doc_base_types():
- 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
@@ -433,7 +466,7 @@ def __doc_base_types():
- LOCK_EXIT
New in PyTango 7.0.0
- """ )
+ """)
document_enum("LogLevel", """
An enumeration representing the LogLevel
@@ -446,7 +479,7 @@ def __doc_base_types():
- LOG_DEBUG
New in PyTango 7.0.0
- """ )
+ """)
document_enum("LogTarget", """
An enumeration representing the LogTarget
@@ -456,7 +489,7 @@ def __doc_base_types():
- LOG_DEVICE
New in PyTango 7.0.0
- """ )
+ """)
document_enum("EventType", """
An enumeration representing event type
@@ -468,10 +501,14 @@ def __doc_base_types():
- USER_EVENT
- ATTR_CONF_EVENT
- DATA_READY_EVENT
+ - INTERFACE_CHANGE_EVENT
+ - PIPE_EVENT
*DATA_READY_EVENT - New in PyTango 7.0.0*
+ *INTERFACE_CHANGE_EVENT - New in PyTango 9.2.2*
+ *PIPE_EVENT - New in PyTango 9.2.2*
- """ )
+ """)
document_enum("AttrSerialModel", """
An enumeration representing the AttrSerialModel
@@ -481,7 +518,7 @@ def __doc_base_types():
- ATTR_BY_USER
New in PyTango 7.1.0
- """ )
+ """)
document_enum("KeepAliveCmdCode", """
An enumeration representing the KeepAliveCmdCode
@@ -489,7 +526,7 @@ def __doc_base_types():
- EXIT_TH
New in PyTango 7.0.0
- """ )
+ """)
document_enum("AccessControlType", """
An enumeration representing the AccessControlType
@@ -498,7 +535,7 @@ def __doc_base_types():
- ACCESS_WRITE
New in PyTango 7.0.0
- """ )
+ """)
document_enum("asyn_req_type", """
An enumeration representing the asynchronous request type
@@ -506,14 +543,14 @@ def __doc_base_types():
- 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
@@ -523,7 +560,7 @@ def __doc_base_types():
- ATTR_ALARM
- ATTR_CHANGING
- ATTR_WARNING
- """ )
+ """)
document_enum("AttrWriteType", """
An enumeration representing the attribute type
@@ -532,7 +569,7 @@ def __doc_base_types():
- READ_WITH_WRITE
- WRITE
- READ_WRITE
- """ )
+ """)
document_enum("AttrDataFormat", """
An enumeration representing the attribute format
@@ -541,14 +578,14 @@ def __doc_base_types():
- SPECTRUM
- IMAGE
- FMT_UNKNOWN
- """ )
+ """)
document_enum("PipeWriteType", """
An enumeration representing the pipe type
- PIPE_READ
- PIPE_READ_WRITE
- """ )
+ """)
document_enum("DevSource", """
An enumeration representing the device source for data
@@ -556,7 +593,7 @@ def __doc_base_types():
- DEV
- CACHE
- CACHE_DEV
- """ )
+ """)
document_enum("ErrSeverity", """
An enumeration representing the error severity
@@ -564,7 +601,7 @@ def __doc_base_types():
- WARN
- ERR
- PANIC
- """ )
+ """)
document_enum("DevState", """
An enumeration representing the device state
@@ -583,14 +620,14 @@ def __doc_base_types():
- ALARM
- DISABLE
- UNKNOWN
- """ )
+ """)
document_enum("DispLevel", """
An enumeration representing the display level
- OPERATOR
- EXPERT
- """ )
+ """)
document_enum("GreenMode", """
An enumeration representing the GreenMode
@@ -600,7 +637,7 @@ def __doc_base_types():
- Gevent
New in PyTango 8.1.0
- """ )
+ """)
ArchiveEventInfo.__doc__ = """
A structure containing available archiving event information for an attribute
@@ -635,7 +672,7 @@ def __doc_base_types():
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
@@ -661,7 +698,7 @@ def __doc_base_types():
Return : (TimeVal) the timestamp of the event
New in PyTango 7.0.0
- """ )
+ """)
AttributeAlarmInfo.__doc__ = """
A structure containing available alarm information for an attribute
@@ -868,7 +905,7 @@ def __doc_base_types():
Return : (TimeVal) the timestamp of the event
New in PyTango 7.0.0
- """ )
+ """)
TimeVal.__doc__ = """
Time value structure with the following members:
@@ -877,6 +914,7 @@ def __doc_base_types():
- tv_usec : microseconds
- tv_nsec : nanoseconds"""
+
def base_types_init(doc=True):
__init_base_types()
if doc:
diff --git a/tango/callback.py b/tango/callback.py
index 27e38e6..8dd6de5 100644
--- a/tango/callback.py
+++ b/tango/callback.py
@@ -19,9 +19,11 @@ __docformat__ = "restructuredtext"
from ._tango import CmdDoneEvent, AttrReadEvent, AttrWrittenEvent
+
def __init_Callback():
pass
+
def __doc_Callback():
CmdDoneEvent.__doc__ = """
This class is used to pass data to the callback method in
@@ -62,6 +64,7 @@ def __doc_Callback():
- ext :
"""
+
def callback_init(doc=True):
__init_Callback()
if doc:
diff --git a/tango/client.py b/tango/client.py
index 15d5217..d373181 100644
--- a/tango/client.py
+++ b/tango/client.py
@@ -30,6 +30,7 @@ _FMT = "pickle"
dumps = functools.partial(_dumps, _FMT)
+
def _command(device, cmd_info, *args, **kwargs):
name = cmd_info.cmd_name
if cmd_info.in_type == CmdArgType.DevEncoded:
@@ -42,10 +43,12 @@ def _command(device, cmd_info, *args, **kwargs):
class _DeviceHelper(object):
-
__CMD_FILTER = set(("init", "state", "status"))
__ATTR_FILTER = set(("state", "status"))
+ __attr_cache = None
+ __cmd_cache = None
+
def __init__(self, dev_name, *args, **kwargs):
self.dev_name = dev_name
self.device = Device(dev_name, *args, **kwargs)
@@ -61,11 +64,8 @@ class _DeviceHelper(object):
self.device.unsubscribe_event(i)
def get_attr_cache(self, refresh=False):
- try:
- cache = self.__attr_cache
- if not cache:
- refresh = True
- except AttributeError:
+ cache = self.__attr_cache
+ if not cache:
refresh = True
if refresh:
cache = {}
@@ -91,11 +91,8 @@ class _DeviceHelper(object):
return cache.get(name)
def get_cmd_cache(self, refresh=False):
- try:
- cache = self.__cmd_cache
- if not cache:
- refresh = True
- except AttributeError:
+ cache = self.__cmd_cache
+ if not cache:
refresh = True
if refresh:
cache = {}
@@ -270,4 +267,3 @@ def connect(obj, signal, slot, event_type=tango.EventType.CHANGE_EVENT):
def disconnect(obj, signal, slot):
"""Experimental function. Not part of the official API"""
return obj._helper.disconnect(signal, slot)
-
diff --git a/tango/codec.py b/tango/codec.py
index 5f99d49..de591e2 100644
--- a/tango/codec.py
+++ b/tango/codec.py
@@ -1,5 +1,6 @@
__all__ = ["loads", "dumps"]
+
def loads(fmt, data):
if fmt.startswith("pickle"):
import pickle
@@ -11,6 +12,7 @@ def loads(fmt, data):
raise TypeError("Format '{0}' not supported".format(fmt))
return loads(data)
+
def dumps(fmt, obj):
if fmt.startswith("pickle"):
import pickle
diff --git a/tango/connection.py b/tango/connection.py
index 7d45f11..b115b79 100644
--- a/tango/connection.py
+++ b/tango/connection.py
@@ -17,7 +17,6 @@ __all__ = ["connection_init"]
__docformat__ = "restructuredtext"
-import operator
import collections
from ._tango import Connection, DeviceData, __CallBackAutoDie, CmdArgType, \
@@ -31,16 +30,18 @@ def __CallBackAutoDie__cmd_ended_aux(self, fn):
def __new_fn(cmd_done_event):
try:
cmd_done_event.argout = cmd_done_event.argout_raw.extract(
- self.defaultCommandExtractAs)
+ 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
@@ -58,20 +59,22 @@ def __get_command_inout_param(self, cmd_name, cmd_param=None):
if isinstance(cmd_param, str):
param.insert(CmdArgType.DevString, cmd_param)
return param
- elif isinstance(cmd_param, collections.Sequence) and all([isinstance(x,str) for x in cmd_param]):
+ elif isinstance(cmd_param, collections.Sequence) 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")
+ 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, green_mode=None, wait=True, timeout=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
@@ -89,7 +92,7 @@ def __Connection__command_inout(self, name, *args, **kwds):
Ignored when green_mode is Synchronous or wait is False.
Return : The result of the command. The type depends on the command. It may be None.
- Throws : ConnectionFailed, CommunicationFailed, DeviceUnlocked, DevFailed from device
+ Throws : ConnectionFailed, CommunicationFailed, DeviceUnlocked, DevFailed from device
TimeoutError (green_mode == Futures) If the future didn't finish executing before the given timeout.
Timeout (green_mode == Gevent) If the async result didn't finish executing before the given timeout.
@@ -106,14 +109,17 @@ def __Connection__command_inout(self, name, *args, **kwds):
return None
else:
return r
+
+
__Connection__command_inout.__name__ = "command_inout"
-def __Connection__command_inout_raw(self, cmd_name, cmd_param = None):
+
+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
@@ -121,21 +127,20 @@ def __Connection__command_inout_raw(self, cmd_name, cmd_param = None):
It can be ommited if the command should not get any argument.
Return : A DeviceData object.
- Throws : ConnectionFailed, CommunicationFailed, DeviceUnlocked, DevFailed from device
+ 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) -> id
- command_inout_asynch(self, cmd_name, cmd_param) -> id
+ command_inout_asynch(self, cmd_name, cmd_param) -> id
command_inout_asynch(self, cmd_name, cmd_param, forget) -> 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
@@ -154,12 +159,12 @@ def __Connection__command_inout_asynch(self, cmd_name, *args):
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
@@ -177,48 +182,51 @@ def __Connection__command_inout_asynch(self, cmd_name, *args):
need to change the global TANGO model to PUSH_CALLBACK.
You can do this with the :meth:`tango.ApiUtil.set_asynch_cb_sub_model`
"""
- if len(args) == 0: # command_inout_asynch()
+ 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 isinstance(args[0], collections.Callable): # command_inout_asynch(lambda)
+ if isinstance(args[0], collections.Callable): # command_inout_asynch(lambda)
cb = __CallBackAutoDie()
cb.cmd_ended = __CallBackAutoDie__cmd_ended_aux(self, 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)
+ elif hasattr(args[0], 'cmd_ended'): # command_inout_asynch(Cbclass)
cb = __CallBackAutoDie()
cb.cmd_ended = __CallBackAutoDie__cmd_ended_aux(self, 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)
+ 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 isinstance(args[1], collections.Callable): #command_inout_asynch( value, lambda)
+ if isinstance(args[1], collections.Callable): # command_inout_asynch( value, lambda)
cb = __CallBackAutoDie()
cb.cmd_ended = __CallBackAutoDie__cmd_ended_aux(self, 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)
+ elif hasattr(args[1], 'cmd_ended'): # command_inout_asynch(value, cbClass)
cb = __CallBackAutoDie()
cb.cmd_ended = __CallBackAutoDie__cmd_ended_aux(self, 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)
+ 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!")
+
+
__Connection__command_inout_asynch.__name__ = "command_inout_asynch"
+
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
@@ -231,7 +239,7 @@ def __Connection__command_inout_reply(self, idx, timeout=None):
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
@@ -252,7 +260,7 @@ def __Connection__command_inout_reply(self, idx, timeout=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)
@@ -260,29 +268,33 @@ def __Connection__command_inout_reply(self, idx, timeout=None):
return None
else:
return r
+
+
__Connection__command_inout_reply.__name__ = "command_inout_reply"
-
+
+
def __init_Connection():
Connection.defaultCommandExtractAs = ExtractAs.Numpy
Connection.command_inout_raw = __Connection__command_inout_raw
Connection.command_inout = green(__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)
def document_static_method(method_name, desc, append=True):
return __document_static_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
@@ -291,7 +303,7 @@ def __doc_Connection():
document_method("get_db_host", """
get_db_host(self) -> str
-
+
Returns a string with the database host.
Parameters : None
@@ -302,7 +314,7 @@ def __doc_Connection():
document_method("get_db_port", """
get_db_port(self) -> str
-
+
Returns a string with the database port.
Parameters : None
@@ -313,7 +325,7 @@ def __doc_Connection():
document_method("get_db_port_num", """
get_db_port_num(self) -> int
-
+
Returns an integer with the database port.
Parameters : None
@@ -324,7 +336,7 @@ def __doc_Connection():
document_method("get_from_env_var", """
get_from_env_var(self) -> bool
-
+
Returns True if determined by environment variable or
False otherwise
@@ -334,10 +346,9 @@ def __doc_Connection():
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.
@@ -350,7 +361,7 @@ def __doc_Connection():
document_method("reconnect", """
reconnect(self, db_used) -> None
-
+
Reconnecto to a CORBA object.
Parameters :
@@ -362,7 +373,7 @@ def __doc_Connection():
document_method("get_idl_version", """
get_idl_version(self) -> int
-
+
Get the version of the Tango Device interface implemented
by the device
@@ -372,7 +383,7 @@ def __doc_Connection():
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
@@ -386,7 +397,7 @@ def __doc_Connection():
document_method("get_timeout_millis", """
get_timeout_millis(self) -> int
-
+
Get the client side timeout in milliseconds
Parameters : None
@@ -395,7 +406,7 @@ def __doc_Connection():
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
@@ -408,7 +419,7 @@ def __doc_Connection():
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.
@@ -421,7 +432,7 @@ def __doc_Connection():
document_method("get_transparency_reconnection", """
get_transparency_reconnection(self) -> bool
-
+
Returns the device transparency reconnection flag.
Parameters : None
@@ -431,7 +442,7 @@ def __doc_Connection():
document_method("set_transparency_reconnection", """
set_transparency_reconnection(self, yesno) -> None
-
+
Set the device transparency reconnection flag
Parameters :
@@ -442,7 +453,7 @@ def __doc_Connection():
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
@@ -457,7 +468,7 @@ def __doc_Connection():
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
@@ -475,17 +486,17 @@ def __doc_Connection():
Throws : AsynCall, AsynReplyNotArrived, CommunicationFailed, DevFailed from device
""")
- #//
- #// Asynchronous methods
- #//
+ # //
+ # // 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
@@ -494,13 +505,13 @@ def __doc_Connection():
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
@@ -512,10 +523,10 @@ def __doc_Connection():
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
@@ -525,27 +536,27 @@ def __doc_Connection():
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
- #//
-
+ # //
+ # // 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
@@ -554,9 +565,9 @@ def __doc_Connection():
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
@@ -567,9 +578,9 @@ def __doc_Connection():
document_method("get_access_right", """
get_access_right(self) -> AccessControlType
-
+
Returns the current access control type
-
+
Parameters : None
Return : (AccessControlType) The current access control type
@@ -578,48 +589,49 @@ def __doc_Connection():
document_static_method("get_fqdn", """
get_fqdn(self) -> str
-
+
Returns the fully qualified domain name
Parameters : None
Return : (str) the fully qualified domain name
-
+
New in PyTango 7.2.0
""")
document_method("is_dbase_used", """
is_dbase_used(self) -> bool
-
+
Returns if the database is being used
-
+
Parameters : None
Return : (bool) True if the database is being used
New in PyTango 7.2.0
""")
-
+
document_method("get_dev_host", """
get_dev_host(self) -> str
-
+
Returns the current host
-
+
Parameters : None
Return : (str) the current host
New in PyTango 7.2.0
""")
-
+
document_method("get_dev_port", """
get_dev_port(self) -> str
-
+
Returns the current port
-
+
Parameters : None
Return : (str) the current port
New in PyTango 7.2.0
""")
-
+
+
def connection_init(doc=True):
__init_Connection()
if doc:
diff --git a/tango/db.py b/tango/db.py
index 42bbec9..e8dbff1 100644
--- a/tango/db.py
+++ b/tango/db.py
@@ -27,44 +27,51 @@ from .utils import is_pure_str, is_non_str_seq, seq_2_StdStringVector, \
seq_2_DbDevInfos, seq_2_DbDevExportInfos, seq_2_DbData, 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.__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, with_dserver=False):
"""
@@ -119,9 +126,9 @@ def __Database__add_server(self, servname, dev_info, with_dserver=False):
"""
if not isinstance(dev_info, collections.Sequence) and \
- not isinstance(dev_info, DbDevInfo):
- raise TypeError('value must be a DbDevInfos, a seq<DbDevInfo> or ' \
- 'a DbDevInfo')
+ not isinstance(dev_info, DbDevInfo):
+ raise TypeError(
+ 'Value must be a DbDevInfos, a seq<DbDevInfo> or a DbDevInfo')
if isinstance(dev_info, DbDevInfos):
pass
@@ -143,6 +150,7 @@ def __Database__add_server(self, servname, dev_info, with_dserver=False):
dev_info.append(dserver_info)
self._add_server(servname, dev_info)
+
def __Database__export_server(self, dev_info):
"""
export_server(self, dev_info) -> None
@@ -158,18 +166,20 @@ def __Database__export_server(self, dev_info):
"""
if not isinstance(dev_info, collections.Sequence) and \
- not isinstance(dev_info, DbDevExportInfo):
- raise TypeError('value must be a DbDevExportInfos, a seq<DbDevExportInfo> or ' \
- 'a DbDevExportInfo')
+ 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),)
+ 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
@@ -197,13 +207,16 @@ def __Database__generic_get_property(self, obj_name, value, f):
new_value.append(DbDatum(k))
ret = value
else:
- raise TypeError('value must be a string, tango.DbDatum, '\
- 'tango.DbData, a sequence or a dictionary')
+ raise TypeError(
+ 'Value must be a string, tango.DbDatum, '
+ 'tango.DbData, a sequence or a dictionary')
f(obj_name, new_value)
- if ret is None: ret = {}
+ 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):
@@ -228,10 +241,12 @@ def __Database__generic_put_property(self, obj_name, value, f):
new_value.append(db_datum)
value = new_value
else:
- raise TypeError('value must be a tango.DbDatum, tango.DbData,'\
- 'a sequence<DbDatum> or a dictionary')
+ raise TypeError(
+ 'Value must be a tango.DbDatum, tango.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):
@@ -257,21 +272,23 @@ def __Database__generic_delete_property(self, obj_name, value, f):
else:
new_value.append(DbDatum(k))
else:
- raise TypeError('value must be a string, tango.DbDatum, '\
- 'tango.DbData, a sequence or a dictionary')
+ raise TypeError(
+ 'Value must be a string, tango.DbDatum, '
+ 'tango.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
@@ -284,6 +301,7 @@ def __Database__put_property(self, obj_name, value):
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>>
@@ -293,7 +311,7 @@ def __Database__get_property(self, obj_name, value):
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
@@ -312,11 +330,14 @@ def __Database__get_property(self, obj_name, 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
@@ -326,7 +347,7 @@ def __Database__delete_property(self, obj_name, value):
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
@@ -341,6 +362,7 @@ def __Database__delete_property(self, obj_name, value):
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>>
@@ -350,7 +372,7 @@ def __Database__get_device_property(self, dev_name, value):
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
@@ -369,6 +391,7 @@ def __Database__get_device_property(self, dev_name, 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
@@ -378,7 +401,7 @@ def __Database__put_device_property(self, dev_name, value):
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
@@ -390,6 +413,7 @@ def __Database__put_device_property(self, dev_name, value):
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
@@ -412,6 +436,7 @@ def __Database__delete_device_property(self, dev_name, value):
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
@@ -440,9 +465,11 @@ def __Database__get_device_property_list(self, dev_name, wildcard, array=None):
return self._get_device_property_list(dev_name, wildcard, array)
elif is_non_str_seq(array):
res = self._get_device_property_list(dev_name, wildcard)
- for e in res: array.append(e)
+ 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>>>
@@ -454,7 +481,7 @@ def __Database__get_device_attribute_property(self, dev_name, value):
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
@@ -497,10 +524,12 @@ def __Database__get_device_attribute_property(self, dev_name, value):
else:
new_value.append(DbDatum(k))
else:
- raise TypeError('value must be a string, tango.DbDatum, '\
- 'tango.DbData, a sequence or a dictionary')
+ raise TypeError(
+ 'Value must be a string, tango.DbDatum, '
+ 'tango.DbData, a sequence or a dictionary')
- if ret is None: ret = {}
+ if ret is None:
+ ret = {}
self._get_device_attribute_property(dev_name, new_value)
@@ -519,6 +548,7 @@ def __Database__get_device_attribute_property(self, dev_name, value):
return ret
+
def __Database__put_device_attribute_property(self, dev_name, value):
"""
put_device_attribute_property( self, dev_name, value) -> None
@@ -528,13 +558,13 @@ def __Database__put_device_attribute_property(self, dev_name, value):
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 tango.DbDatum
@@ -560,15 +590,17 @@ def __Database__put_device_attribute_property(self, dev_name, value):
seq_2_StdStringVector(v2, db_datum.value_string)
else:
if not is_pure_str(v2):
- v2 = repr(v2)
+ v2 = repr(v2)
db_datum.value_string.append(v2)
new_value.append(db_datum)
value = new_value
else:
- raise TypeError('value must be a tango.DbData,'\
- 'a sequence<DbDatum> or a dictionary')
+ raise TypeError(
+ 'Value must be a tango.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
@@ -600,11 +632,13 @@ def __Database__delete_device_attribute_property(self, dev_name, value):
for k2 in v1:
new_value.append(DbDatum(k2))
else:
- raise TypeError('value must be a string, tango.DbDatum, '\
- 'tango.DbData, a sequence or a dictionary')
+ raise TypeError(
+ 'Value must be a string, tango.DbDatum, '
+ 'tango.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>>
@@ -614,7 +648,7 @@ def __Database__get_class_property(self, class_name, value):
Parameters :
- class_name : (str) class name
- value : can be one of the following:
-
+
1. str [in] - single property data to be fetched
2. tango.DbDatum [in] - single property data to be fetched
3. tango.DbData [in,out] - several property data to be fetched
@@ -633,6 +667,7 @@ def __Database__get_class_property(self, class_name, 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
@@ -653,6 +688,7 @@ def __Database__put_class_property(self, class_name, value):
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
@@ -662,7 +698,7 @@ def __Database__delete_class_property(self, class_name, value):
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
@@ -672,12 +708,13 @@ def __Database__delete_class_property(self, class_name, value):
(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>>
@@ -689,7 +726,7 @@ def __Database__get_class_attribute_property(self, class_name, value):
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
@@ -732,12 +769,14 @@ def __Database__get_class_attribute_property(self, class_name, value):
else:
new_value.append(DbDatum(k))
else:
- raise TypeError('value must be a string, tango.DbDatum, '\
- 'tango.DbData, a sequence or a dictionary')
+ raise TypeError(
+ 'Value must be a string, tango.DbDatum, '
+ 'tango.DbData, a sequence or a dictionary')
self._get_class_attribute_property(class_name, new_value)
- if ret is None: ret = {}
+ if ret is None:
+ ret = {}
nb_items = len(new_value)
i = 0
@@ -754,6 +793,7 @@ def __Database__get_class_attribute_property(self, class_name, value):
return ret
+
def __Database__put_class_attribute_property(self, class_name, value):
"""
put_class_attribute_property(self, class_name, value) -> None
@@ -763,13 +803,13 @@ def __Database__put_class_attribute_property(self, class_name, value):
Parameters :
- class_name : (str) class name
- propdata : can be one of the following:
-
+
1. tango.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 tango.DbDatum
@@ -799,10 +839,12 @@ def __Database__put_class_attribute_property(self, class_name, value):
new_value.append(db_datum)
value = new_value
else:
- raise TypeError('value must be a tango.DbData,'\
- 'a sequence<DbDatum> or a dictionary')
+ raise TypeError(
+ 'Value must be a tango.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
@@ -812,13 +854,13 @@ def __Database__delete_class_attribute_property(self, class_name, value):
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
@@ -837,11 +879,12 @@ def __Database__delete_class_attribute_property(self, class_name, value):
for k2 in v1:
new_value.append(DbDatum(k2))
else:
- raise TypeError('value must be a DbDatum, DbData, '\
- 'a sequence or a dictionary')
+ 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')
@@ -852,47 +895,50 @@ def __Database__get_service_list(self, filter='.*'):
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.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
-
+ 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(),
+ 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
+
+ The constructor uses the TANGO_HOST env. variable to determine which
instance of the Database to connect to."""
document_method("write_filedatabase", """
@@ -904,7 +950,7 @@ def __doc_Database():
Return : None
New in PyTango 7.0.0
- """ )
+ """)
document_method("reread_filedatabase", """
reread_filedatabase(self) -> None
@@ -915,7 +961,7 @@ def __doc_Database():
Return : None
New in PyTango 7.0.0
- """ )
+ """)
document_method("build_connection", """
build_connection(self) -> None
@@ -926,7 +972,7 @@ def __doc_Database():
Return : None
New in PyTango 7.0.0
- """ )
+ """)
document_method("check_tango_host", """
check_tango_host(self, tango_host_env) -> None
@@ -939,7 +985,7 @@ def __doc_Database():
Return : None
New in PyTango 7.0.0
- """ )
+ """)
document_method("check_access_control", """
check_access_control(self, dev_name) -> AccessControlType
@@ -951,7 +997,7 @@ def __doc_Database():
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
@@ -962,7 +1008,7 @@ def __doc_Database():
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
@@ -974,7 +1020,7 @@ def __doc_Database():
Return : None
New in PyTango 7.0.0
- """ )
+ """)
document_method("get_access_except_errors", """
get_access_except_errors(self) -> DevErrorList
@@ -985,7 +1031,7 @@ def __doc_Database():
Return : DevErrorList
New in PyTango 7.0.0
- """ )
+ """)
document_method("is_multi_tango_host", """
is_multi_tango_host(self) -> bool
@@ -996,7 +1042,7 @@ def __doc_Database():
Return : True if multi tango host or False otherwise
New in PyTango 7.1.4
- """ )
+ """)
document_method("get_file_name", """
get_file_name(self) -> str
@@ -1008,11 +1054,10 @@ def __doc_Database():
Return : a string containing the database file name
Throws : DevFailed
-
+
New in PyTango 7.2.0
- """ )
+ """)
-
document_method("get_info", """
get_info(self) -> str
@@ -1020,7 +1065,7 @@ def __doc_Database():
Parameters : None
Return : a multiline string
- """ )
+ """)
document_method("get_host_list", """
get_host_list(self) -> DbDatum
@@ -1031,7 +1076,7 @@ def __doc_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
@@ -1044,7 +1089,7 @@ def __doc_Database():
Return : DbDatum with the list of available services
New in PyTango 3.0.4
- """ )
+ """)
document_method("get_device_service_list", """
get_device_service_list(self, dev_name) -> DbDatum
@@ -1056,8 +1101,8 @@ def __doc_Database():
Return : DbDatum with the list of services
New in PyTango 8.1.0
- """ )
-
+ """)
+
document_method("register_service", """
register_service(self, serv_name, inst_name, dev_name) -> None
@@ -1070,7 +1115,7 @@ def __doc_Database():
Return : None
New in PyTango 3.0.4
- """ )
+ """)
document_method("unregister_service", """
unregister_service(self, serv_name, inst_name) -> None
@@ -1083,7 +1128,7 @@ def __doc_Database():
Return : None
New in PyTango 3.0.4
- """ )
+ """)
document_method("add_device", """
add_device(self, dev_info) -> None
@@ -1101,7 +1146,7 @@ def __doc_Database():
Parameters :
- dev_info : (DbDevInfo) device information
Return : None
- """ )
+ """)
document_method("delete_device", """
delete_device(self, dev_name) -> None
@@ -1111,7 +1156,7 @@ def __doc_Database():
Parameters :
- dev_name : (str) device name
Return : None
- """ )
+ """)
document_method("import_device", """
import_device(self, dev_name) -> DbDevImportInfo
@@ -1128,7 +1173,7 @@ def __doc_Database():
Parameters :
- dev_name : (str) device name
Return : DbDevImportInfo
- """ )
+ """)
document_method("get_device_info", """
get_device_info(self, dev_name) -> DbDevFullInfo
@@ -1150,9 +1195,9 @@ def __doc_Database():
Parameters :
- dev_name : (str) device name
Return : DbDevFullInfo
-
+
New in PyTango 8.1.0
- """ )
+ """)
document_method("export_device", """
export_device(self, dev_export) -> None
@@ -1171,7 +1216,7 @@ def __doc_Database():
Parameters :
- dev_export : (DbDevExportInfo) export information
Return : None
- """ )
+ """)
document_method("unexport_device", """
unexport_device(self, dev_name) -> None
@@ -1184,7 +1229,7 @@ def __doc_Database():
Parameters :
- dev_name : (str) device name
Return : None
- """ )
+ """)
document_method("get_device_name", """
get_device_name(self, serv_name, class_name) -> DbDatum
@@ -1196,7 +1241,7 @@ def __doc_Database():
- 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
@@ -1207,7 +1252,7 @@ def __doc_Database():
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
@@ -1219,7 +1264,7 @@ def __doc_Database():
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
@@ -1231,7 +1276,7 @@ def __doc_Database():
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
@@ -1243,7 +1288,7 @@ def __doc_Database():
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
@@ -1256,7 +1301,7 @@ def __doc_Database():
.. deprecated:: 8.1.0
Use :meth:`~tango.Database.get_device_from_alias` instead
- """ )
+ """)
document_method("get_alias", """
get_alias(self, alias) -> str
@@ -1268,10 +1313,10 @@ def __doc_Database():
Return : alias
New in PyTango 3.0.4
-
+
.. deprecated:: 8.1.0
Use :meth:`~tango.Database.get_alias_from_device` instead
- """ )
+ """)
document_method("get_device_from_alias", """
get_device_from_alias(self, alias) -> str
@@ -1281,9 +1326,9 @@ def __doc_Database():
Parameters :
- alias : (str) alias
Return : device name
-
+
New in PyTango 8.1.0
- """ )
+ """)
document_method("get_alias_from_device", """
get_alias_from_device(self, alias) -> str
@@ -1295,7 +1340,7 @@ def __doc_Database():
Return : alias
New in PyTango 8.1.0
- """ )
+ """)
document_method("get_device_alias_list", """
get_device_alias_list(self, filter) -> DbDatum
@@ -1308,7 +1353,7 @@ def __doc_Database():
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
@@ -1318,7 +1363,7 @@ def __doc_Database():
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
@@ -1330,7 +1375,7 @@ def __doc_Database():
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
@@ -1340,7 +1385,7 @@ def __doc_Database():
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
@@ -1352,7 +1397,7 @@ def __doc_Database():
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
@@ -1363,7 +1408,7 @@ def __doc_Database():
- dev_name : (str) device name
- alias : (str) alias name
Return : None
- """ )
+ """)
document_method("delete_device_alias", """
delete_device_alias(self, alias) -> void
@@ -1373,7 +1418,7 @@ def __doc_Database():
Parameters :
- alias : (str) alias name
Return : None
- """ )
+ """)
document_method("_add_server", """
_add_server(self, serv_name, dev_info) -> None
@@ -1385,7 +1430,7 @@ def __doc_Database():
- serv_name : (str) server name
- dev_info : (DbDevInfos) server device(s) information
Return : None
- """ )
+ """)
document_method("delete_server", """
delete_server(self, server) -> None
@@ -1396,7 +1441,7 @@ def __doc_Database():
- 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
@@ -1409,7 +1454,7 @@ def __doc_Database():
Return : None
Throws : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
- """ )
+ """)
document_method("unexport_server", """
unexport_server(self, server) -> None
@@ -1422,7 +1467,7 @@ def __doc_Database():
Return : None
Throws : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
- """ )
+ """)
document_method("rename_server", """
rename_server(self, old_ds_name, new_ds_name) -> None
@@ -1435,9 +1480,9 @@ def __doc_Database():
Return : None
Throws : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
-
+
New in PyTango 8.1.0
- """ )
+ """)
document_method("get_server_info", """
get_server_info(self, server) -> DbServerInfo
@@ -1452,7 +1497,7 @@ def __doc_Database():
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
@@ -1466,7 +1511,7 @@ def __doc_Database():
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
@@ -1481,7 +1526,7 @@ def __doc_Database():
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
@@ -1499,7 +1544,7 @@ def __doc_Database():
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
@@ -1512,7 +1557,7 @@ def __doc_Database():
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
@@ -1526,7 +1571,7 @@ def __doc_Database():
Throws : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
New in PyTango 3.0.4
- """ )
+ """)
document_method("get_server_list", """
get_server_list(self) -> DbDatum
@@ -1539,7 +1584,7 @@ def __doc_Database():
Parameters :
- wildcard : (str) host wildcard (ex: Serial/\*)
Return : DbDatum containing list of registered servers
- """ )
+ """)
document_method("get_host_server_list", """
get_host_server_list(self, host_name) -> DbDatum
@@ -1553,7 +1598,7 @@ def __doc_Database():
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
@@ -1570,7 +1615,7 @@ def __doc_Database():
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
@@ -1587,7 +1632,7 @@ def __doc_Database():
Return : None
Throws : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
- """ )
+ """)
document_method("_get_property_forced", """
_get_property_forced(self, obj_name, props) -> None
@@ -1606,7 +1651,7 @@ def __doc_Database():
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
@@ -1620,7 +1665,7 @@ def __doc_Database():
Return : None
Throws : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
- """ )
+ """)
document_method("get_property_history", """
get_property_history(self, obj_name, prop_name) -> DbHistoryList
@@ -1637,7 +1682,7 @@ def __doc_Database():
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
@@ -1653,7 +1698,7 @@ def __doc_Database():
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
@@ -1670,7 +1715,7 @@ def __doc_Database():
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
@@ -1687,7 +1732,7 @@ def __doc_Database():
Return : None
Throws : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
- """ )
+ """)
document_method("_put_device_property", """
_put_device_property(self, dev_name, props) -> None
@@ -1701,7 +1746,7 @@ def __doc_Database():
Return : None
Throws : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
- """ )
+ """)
document_method("_delete_device_property", """
_delete_device_property(self, dev_name, props) -> None
@@ -1715,7 +1760,7 @@ def __doc_Database():
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
@@ -1733,7 +1778,7 @@ def __doc_Database():
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
@@ -1753,7 +1798,7 @@ def __doc_Database():
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
@@ -1770,7 +1815,7 @@ def __doc_Database():
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
@@ -1784,7 +1829,7 @@ def __doc_Database():
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
@@ -1807,7 +1852,7 @@ def __doc_Database():
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
@@ -1820,13 +1865,13 @@ def __doc_Database():
- dev_name : (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
@@ -1842,7 +1887,7 @@ def __doc_Database():
Return : None
Throws : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
- """ )
+ """)
document_method("_put_class_property", """
_put_class_property(self, class_name, props) -> None
@@ -1856,7 +1901,7 @@ def __doc_Database():
Return : None
Throws : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
- """ )
+ """)
document_method("_delete_class_property", """
_delete_class_property(self, class_name, props) -> None
@@ -1870,7 +1915,7 @@ def __doc_Database():
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
@@ -1887,7 +1932,7 @@ def __doc_Database():
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
@@ -1901,7 +1946,7 @@ def __doc_Database():
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
@@ -1913,7 +1958,7 @@ def __doc_Database():
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
@@ -1933,7 +1978,7 @@ def __doc_Database():
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
@@ -1947,7 +1992,7 @@ def __doc_Database():
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
@@ -1964,7 +2009,7 @@ def __doc_Database():
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
@@ -1980,7 +2025,7 @@ def __doc_Database():
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
@@ -1992,10 +2037,10 @@ def __doc_Database():
Return : full attribute name
Throws : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
-
+
.. deprecated:: 8.1.0
Use :meth:`~tango.Database.get_attribute_from_alias` instead
- """ )
+ """)
document_method("get_attribute_from_alias", """
get_attribute_from_alias(self, alias) -> str
@@ -2007,9 +2052,9 @@ def __doc_Database():
Return : full attribute name
Throws : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
-
+
New in PyTango 8.1.0
- """ )
+ """)
document_method("get_alias_from_attribute", """
get_alias_from_attribute(self, attr_name) -> str
@@ -2021,10 +2066,10 @@ def __doc_Database():
Return : attribute alias
Throws : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
-
+
New in PyTango 8.1.0
- """ )
-
+ """)
+
document_method("get_attribute_alias_list", """
get_attribute_alias_list(self, filter) -> DbDatum
@@ -2040,7 +2085,7 @@ def __doc_Database():
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
@@ -2056,7 +2101,7 @@ def __doc_Database():
Return : None
Throws : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
- """ )
+ """)
document_method("delete_attribute_alias", """
delete_attribute_alias(self, alias) -> None
@@ -2068,7 +2113,7 @@ def __doc_Database():
Return : None
Throws : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
- """ )
+ """)
document_method("export_event", """
export_event(self, event_data) -> None
@@ -2082,7 +2127,7 @@ def __doc_Database():
Throws : ConnectionFailed, CommunicationFailed, DevFailed from device (DB_SQLError)
New in PyTango 7.0.0
- """ )
+ """)
document_method("unexport_event", """
unexport_event(self, event) -> None
@@ -2096,7 +2141,8 @@ def __doc_Database():
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):
@@ -2126,7 +2172,7 @@ def __doc_DbDatum():
Return : the number of separate elements in the value.
New in PyTango 7.0.0
- """ )
+ """)
document_method("is_empty", """
is_empty(self) -> bool
@@ -2139,38 +2185,42 @@ def __doc_DbDatum():
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 : (str) device name
- ior : (str) CORBA reference of the device
- host : name of the computer hosting the server
- version : (str) version
- pid : process identifier"""
+
def __doc_DbDevImportInfo():
DbDevImportInfo.__doc__ = """
import info for a device (should be retrived from the database) with
the following members:
-
+
- name : (str) device name
- exported : 1 if device is running, 0 else
- ior : (str)CORBA reference of the device
- version : (str) version"""
+
def __doc_DbDevInfo():
DbDevInfo.__doc__ = """
A structure containing available information for a device with
the following members:
-
+
- name : (str) name
- _class : (str) device class
- server : (str) server"""
+
def __doc_DbHistory():
def document_method(method_name, desc, append=True):
return __document_method(DbHistory, method_name, desc, append)
@@ -2185,7 +2235,7 @@ def __doc_DbHistory():
Parameters : None
Return : (str) property name
- """ )
+ """)
document_method("get_attribute_name", """
get_attribute_name(self) -> str
@@ -2194,7 +2244,7 @@ def __doc_DbHistory():
Parameters : None
Return : (str) attribute name
- """ )
+ """)
document_method("get_date", """
get_date(self) -> str
@@ -2203,7 +2253,7 @@ def __doc_DbHistory():
Parameters : None
Return : (str) update date
- """ )
+ """)
document_method("get_value", """
get_value(self) -> DbDatum
@@ -2212,7 +2262,7 @@ def __doc_DbHistory():
Parameters : None
Return : (DbDatum) a COPY of the property value
- """ )
+ """)
document_method("is_deleted", """
is_deleted(self) -> bool
@@ -2221,22 +2271,24 @@ def __doc_DbHistory():
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) name
- host : (str) host
- mode : (str) mode
- level : (str) level"""
+
def __doc_DbServerData():
def document_method(method_name, desc, append=True):
return __document_method(DbServerData, method_name, desc, append)
-
+
DbServerData.__doc__ = """\
A structure used for moving DS from one tango host to another.
Create a new instance by: DbServerData(<server name>, <server instance>)"""
@@ -2248,19 +2300,19 @@ def __doc_DbServerData():
Parameters : None
Return : (str) the full server name
- """ )
+ """)
document_method("put_in_database", """
put_in_database(self, tg_host) -> None
- Store all the data related to the device server process in the
+ Store all the data related to the device server process in the
database specified by the input arg.
Parameters :
- tg_host : (str) The tango host for the new database
Return : None
- """ )
-
+ """)
+
document_method("already_exist", """
already_exist(self, tg_host) -> bool
@@ -2270,7 +2322,7 @@ def __doc_DbServerData():
Parameters :
- tg_host : (str) The tango host for the new database
Return : (str) True in case any of the device is already known. False otherwise
- """ )
+ """)
document_method("remove", """
remove(self) -> None
@@ -2281,14 +2333,14 @@ def __doc_DbServerData():
Parameters :
- tg_host : (str) The tango host for the new database
Return : None
- """ )
-
-
+ """)
+
+
def db_init(doc=True):
__init_DbDatum()
if doc:
__doc_DbDatum()
-
+
__init_Database()
if doc:
__doc_Database()
@@ -2298,4 +2350,3 @@ def db_init(doc=True):
__doc_DbHistory()
__doc_DbServerInfo()
__doc_DbServerData()
-
diff --git a/tango/device_attribute.py b/tango/device_attribute.py
index 5b3d681..95c571d 100644
--- a/tango/device_attribute.py
+++ b/tango/device_attribute.py
@@ -22,24 +22,33 @@ import copy
from .utils import document_method as __document_method
from ._tango import DeviceAttribute, ExtractAs
+
def __DeviceAttribute__get_data(self):
return self.get_data_raw().extract()
+
def __DeviceAttribute__init(self, da=None):
if da is None:
DeviceAttribute.__init_orig(self)
else:
DeviceAttribute.__init_orig(self, da)
- 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
+ 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)
@@ -49,13 +58,13 @@ def __doc_DeviceAttribute():
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)
@@ -68,7 +77,7 @@ def __doc_DeviceAttribute():
- 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
@@ -79,12 +88,12 @@ def __doc_DeviceAttribute():
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>
@@ -94,39 +103,41 @@ def __doc_DeviceAttribute():
Parameters : None
Return : (sequence<DevError>)
- """ )
+ """)
document_method("set_w_dim_x", """
set_w_dim_x(self, val) -> None
Sets the write value dim x.
- Parameters :
+ Parameters :
- val : (int) new write dim x
-
+
Return : None
-
+
New in PyTango 8.0.0
- """ )
+ """)
document_method("set_w_dim_y", """
set_w_dim_y(self, val) -> None
Sets the write value dim y.
- Parameters :
+ Parameters :
- val : (int) new write dim y
-
+
Return : None
-
+
New in PyTango 8.0.0
- """ )
-
+ """)
+
+
def __init_DeviceAttribute():
DeviceAttribute.__init_orig = DeviceAttribute.__init__
DeviceAttribute.__init__ = __DeviceAttribute__init
DeviceAttribute.ExtractAs = ExtractAs
+
def device_attribute_init(doc=True):
__init_DeviceAttribute()
if doc:
diff --git a/tango/device_class.py b/tango/device_class.py
index 4632ed8..3f95dc0 100644
--- a/tango/device_class.py
+++ b/tango/device_class.py
@@ -15,7 +15,7 @@ This is an internal PyTango module.
from __future__ import print_function
-__all__ = [ "DeviceClass", "device_class_init" ]
+__all__ = ["DeviceClass", "device_class_init"]
__docformat__ = "restructuredtext"
@@ -39,7 +39,7 @@ class PropUtil:
"""An internal Property util class"""
scalar_int_types = (CmdArgType.DevShort, CmdArgType.DevUShort,
- CmdArgType.DevInt, CmdArgType.DevLong, CmdArgType.DevULong,)
+ CmdArgType.DevInt, CmdArgType.DevLong, CmdArgType.DevULong,)
scalar_long_types = (CmdArgType.DevLong64, CmdArgType.DevULong64)
@@ -73,15 +73,15 @@ class PropUtil:
"""
for name in class_prop:
type = self.get_property_type(name, class_prop)
- val = self.get_property_values(name, class_prop)
- val = self.values2string(val, type)
+ 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:
type = self.get_property_type(name, dev_prop)
- val = self.get_property_values(name, dev_prop)
- val = self.values2string(val, type)
+ 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)
@@ -98,7 +98,7 @@ class PropUtil:
Return : None"""
# initialize default values
- if class_prop == {} or Util._UseDb == False:
+ if class_prop == {} or not Util._UseDb:
return
# call database to get properties
@@ -107,7 +107,7 @@ class PropUtil:
# if value defined in database, store it
for name in class_prop:
if props[name]:
- type = self.get_property_type(name, class_prop)
+ type = self.get_property_type(name, class_prop)
values = self.stringArray2values(props[name], type)
self.set_property_values(name, class_prop, values)
else:
@@ -126,10 +126,10 @@ class PropUtil:
Return : None"""
# initialize default properties
- if dev_prop == {} or Util._UseDb == False:
+ if dev_prop == {} or not Util._UseDb:
return
- # Call database to get properties
+ # Call database to get properties
props = self.db.get_device_property(dev.get_name(), list(dev_prop.keys()))
# if value defined in database, store it
for name in dev_prop:
@@ -150,7 +150,7 @@ class PropUtil:
if not self.is_empty_seq(values):
self.set_property_values(name, dev_prop, values)
else:
- # Try to get it from class property
+ # 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):
@@ -229,7 +229,7 @@ class PropUtil:
Return : (obj) the value for the given property name"""
try:
tg_type = self.get_property_type(prop_name, properties)
- val = properties[prop_name][2]
+ val = properties[prop_name][2]
except:
val = []
@@ -265,6 +265,7 @@ class PropUtil:
def __DeviceClass__init__(self, name):
DeviceClass.__init_orig__(self, name)
self.dyn_att_added_methods = []
+ self.dyn_cmd_added_methods = []
try:
pu = self.prop_util = PropUtil()
self.py_dev_list = []
@@ -274,7 +275,7 @@ def __DeviceClass__init__(self, name):
for prop_name in self.class_property_list:
if not hasattr(self, prop_name):
setattr(self, prop_name, pu.get_property_values(prop_name,
- self.class_property_list))
+ self.class_property_list))
except DevFailed as df:
print("PyDS: %s: A Tango error occured in the constructor:" % name)
Except.print_exception(df)
@@ -282,11 +283,14 @@ def __DeviceClass__init__(self, name):
print("PyDS: %s: An error occured in the constructor:" % name)
print(str(e))
+
def __DeviceClass__str__(self):
return '%s(%s)' % (self.__class__.__name__, self.get_name())
+
def __DeviceClass__repr__(self):
- return '%s(%s)' % (self.__class__.__name__, self.get_name())
+ return '%s(%s)' % (self.__class__.__name__, self.get_name())
+
def __throw_create_attribute_exception(msg):
"""
@@ -296,6 +300,7 @@ def __throw_create_attribute_exception(msg):
Except.throw_exception("PyDs_WrongAttributeDefinition", msg,
"create_attribute()")
+
def __throw_create_command_exception(msg):
"""
Helper method to throw DevFailed exception when inside
@@ -304,18 +309,19 @@ def __throw_create_command_exception(msg):
Except.throw_exception("PyDs_WrongCommandDefinition", msg,
"create_command()")
+
def __DeviceClass__create_user_default_attr_prop(self, attr_name, extra_info):
"""for internal usage only"""
p = UserDefaultAttrProp()
for k, v in extra_info.items():
k_lower = k.lower()
- method_name = "set_%s" % k_lower.replace(' ','_')
+ 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'):
+ elif k_lower not in ('display level', 'polling period', 'memorized'):
name = self.get_name()
msg = "Wrong definition of attribute %s in " \
"class %s\nThe object extra information '%s' " \
@@ -323,6 +329,7 @@ def __DeviceClass__create_user_default_attr_prop(self, attr_name, extra_info):
self.__throw_create_attribute_exception(msg)
return p
+
def __DeviceClass__attribute_factory(self, attr_list):
"""for internal usage only"""
for attr_name, attr_info in self.attr_list.items():
@@ -330,19 +337,23 @@ def __DeviceClass__attribute_factory(self, attr_list):
attr_data = attr_info
else:
attr_data = AttrData(attr_name, self.get_name(), attr_info)
- 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)
+ if attr_data.forward:
+ self._create_fwd_attribute(attr_list, attr_data.name, attr_data.att_prop)
+ else:
+ 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 __DeviceClass__pipe_factory(self, pipe_list):
"""for internal usage only"""
@@ -359,6 +370,7 @@ def __DeviceClass__pipe_factory(self, pipe_list):
pipe_data.is_allowed_name,
pipe_data.pipe_prop)
+
def __DeviceClass__command_factory(self):
"""for internal usage only"""
name = self.get_name()
@@ -373,6 +385,7 @@ def __DeviceClass__command_factory(self):
for cmd_name, cmd_info in self.cmd_list.items():
__create_command(self, deviceimpl_class, cmd_name, cmd_info)
+
def __create_command(self, deviceimpl_class, cmd_name, cmd_info):
"""for internal usage only"""
name = self.get_name()
@@ -529,9 +542,11 @@ def __create_command(self, deviceimpl_class, cmd_name, cmd_info):
display_level, default_command,
polling_period, is_allowed_name)
+
def __DeviceClass__new_device(self, klass, dev_class, dev_name):
return klass(dev_class, dev_name)
+
def __DeviceClass__device_factory(self, device_list):
"""for internal usage only"""
@@ -563,6 +578,7 @@ def __DeviceClass__device_factory(self, device_list):
self.export_device(dev, dev.get_name())
self.py_dev_list += tmp_dev_list
+
def __DeviceClass__create_device(self, device_name, alias=None, cb=None):
"""
create_device(self, device_name, alias=None, cb=None) -> None
@@ -571,7 +587,7 @@ def __DeviceClass__create_device(self, device_name, alias=None, cb=None):
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
+ 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
@@ -595,6 +611,7 @@ def __DeviceClass__create_device(self, device_name, alias=None, cb=None):
util = Util.instance()
util.create_device(self.get_name(), device_name, alias=alias, cb=cb)
+
def __DeviceClass__delete_device(self, device_name):
"""
delete_device(self, klass_name, device_name) -> None
@@ -616,7 +633,8 @@ def __DeviceClass__delete_device(self, device_name):
util = Util.instance()
util.delete_device(self.get_name(), device_name)
-def __DeviceClass__dyn_attr(self,device_list):
+
+def __DeviceClass__dyn_attr(self, device_list):
"""
dyn_attr(self,device_list) -> None
@@ -629,7 +647,8 @@ def __DeviceClass__dyn_attr(self,device_list):
Return : None"""
pass
-def __DeviceClass__device_destroyer(self,name):
+
+def __DeviceClass__device_destroyer(self, name):
"""for internal usage only"""
name = name.lower()
for d in self.py_dev_list:
@@ -643,7 +662,7 @@ def __DeviceClass__device_destroyer(self,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")
+ Except.throw_exception("PyAPI_CantDestroyDevice", err_mess, "DeviceClass.device_destroyer")
def __DeviceClass__device_name_factory(self, dev_name_list):
@@ -661,7 +680,7 @@ def __DeviceClass__device_name_factory(self, dev_name_list):
Return : None"""
pass
-
+
def __init_DeviceClass():
DeviceClass.class_property_list = {}
DeviceClass.device_property_list = {}
@@ -677,7 +696,7 @@ def __init_DeviceClass():
DeviceClass._pipe_factory = __DeviceClass__pipe_factory
DeviceClass._command_factory = __DeviceClass__command_factory
DeviceClass._new_device = __DeviceClass__new_device
-
+
DeviceClass.device_factory = __DeviceClass__device_factory
DeviceClass.create_device = __DeviceClass__create_device
DeviceClass.delete_device = __DeviceClass__delete_device
@@ -687,13 +706,12 @@ def __init_DeviceClass():
def __doc_DeviceClass():
-
DeviceClass.__doc__ = """
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
"""
-
+
def document_method(method_name, desc, append=True):
return __document_method(DeviceClass, method_name, desc, append)
@@ -707,7 +725,7 @@ def __doc_DeviceClass():
- corba_dev_name : (str) CORBA device name. Default value is 'Unused'
Return : None
- """ )
+ """)
document_method("register_signal", """
register_signal(self, signo) -> None
@@ -726,12 +744,12 @@ def __doc_DeviceClass():
- signo : (int) signal identifier
- own_handler : (bool) true if you want the device signal handler
to be executed in its own handler instead of being
- executed by the signal thread. If this parameter
+ executed by the signal thread. If this parameter
is set to true, care should be taken on how the
handler is written. A default false value is provided
-
+
Return : None
- """ )
+ """)
document_method("unregister_signal", """
unregister_signal(self, signo) -> None
@@ -743,7 +761,7 @@ def __doc_DeviceClass():
Parameters :
- signo : (int) signal identifier
Return : None
- """ )
+ """)
document_method("signal_handler", """
signal_handler(self, signo) -> None
@@ -757,7 +775,7 @@ def __doc_DeviceClass():
Parameters :
- signo : (int) signal identifier
Return : None
- """ )
+ """)
document_method("get_name", """
get_name(self) -> str
@@ -766,7 +784,7 @@ def __doc_DeviceClass():
Parameters : None
Return : (str) the TANGO device class name.
- """ )
+ """)
document_method("get_type", """
get_type(self) -> str
@@ -775,7 +793,7 @@ def __doc_DeviceClass():
Parameters : None
Return : (str) the TANGO device type name
- """ )
+ """)
document_method("get_doc_url", """
get_doc_url(self) -> str
@@ -784,7 +802,7 @@ def __doc_DeviceClass():
Parameters : None
Return : (str) the TANGO device type name
- """ )
+ """)
document_method("set_type", """
set_type(self, dev_type) -> None
@@ -794,7 +812,7 @@ def __doc_DeviceClass():
Parameters :
- dev_type : (str) the new TANGO device type name
Return : None
- """ )
+ """)
document_method("get_cvs_tag", """
get_cvs_tag(self) -> str
@@ -803,7 +821,7 @@ def __doc_DeviceClass():
Parameters : None
Return : (str) cvs tag
- """ )
+ """)
document_method("get_cvs_location", """
get_cvs_location(self) -> None
@@ -812,7 +830,7 @@ def __doc_DeviceClass():
Parameters : None
Return : (str) cvs location
- """ )
+ """)
document_method("get_device_list", """
get_device_list(self) -> sequence<tango.DeviceImpl>
@@ -821,7 +839,7 @@ def __doc_DeviceClass():
Parameters : None
Return : (sequence<tango.DeviceImpl>) list of tango.DeviceImpl objects for this class
- """ )
+ """)
document_method("get_command_list", """
get_command_list(self) -> sequence<tango.Command>
@@ -830,9 +848,9 @@ def __doc_DeviceClass():
Parameters : None
Return : (sequence<tango.Command>) list of tango.Command objects for this class
-
+
New in PyTango 8.0.0
- """ )
+ """)
document_method("get_cmd_by_name", """
get_cmd_by_name(self, (str)cmd_name) -> tango.Command
@@ -842,10 +860,10 @@ def __doc_DeviceClass():
Parameters :
- cmd_name : (str) command name
Return : (tango.Command) tango.Command object
-
+
New in PyTango 8.0.0
- """ )
-
+ """)
+
document_method("add_wiz_dev_prop", """
add_wiz_dev_prop(self, str, str) -> None
add_wiz_dev_prop(self, str, str, str) -> None
@@ -854,7 +872,7 @@ def __doc_DeviceClass():
Parameters : None
Return : None
- """ )
+ """)
document_method("add_wiz_class_prop", """
add_wiz_class_prop(self, str, str) -> None
@@ -864,7 +882,8 @@ def __doc_DeviceClass():
Parameters : None
Return : None
- """ )
+ """)
+
def device_class_init(doc=True):
__init_DeviceClass()
diff --git a/tango/device_data.py b/tango/device_data.py
index 20198da..42da29c 100644
--- a/tango/device_data.py
+++ b/tango/device_data.py
@@ -20,12 +20,15 @@ __docformat__ = "restructuredtext"
from .utils import document_method as __document_method
from ._tango 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)
@@ -43,7 +46,7 @@ def __doc_DeviceData():
Parameters : None
Return : Whatever is stored there, or None.
- """ )
+ """)
document_method("insert", """
insert(self, data_type, value) -> None
@@ -51,10 +54,10 @@ def __doc_DeviceData():
Inserts a value in the DeviceData.
Parameters :
- - data_type :
+ - data_type :
- value : (any) The value to insert
Return : Whatever is stored there, or None.
- """ )
+ """)
document_method("is_empty", """
is_empty(self) -> bool
@@ -65,7 +68,7 @@ def __doc_DeviceData():
Parameters : None
Return : True or False depending on whether the DeviceData object
contains data or not.
- """ )
+ """)
document_method("get_type", """
get_type(self) -> CmdArgType
@@ -75,10 +78,10 @@ def __doc_DeviceData():
Parameters : None
Return : The content arg type.
- """ )
+ """)
+
def device_data_init(doc=True):
__init_DeviceData()
if doc:
__doc_DeviceData()
-
diff --git a/tango/device_proxy.py b/tango/device_proxy.py
index 2f20fd4..4a90c35 100644
--- a/tango/device_proxy.py
+++ b/tango/device_proxy.py
@@ -11,9 +11,8 @@
"""Define python methods for DeviceProxy object."""
-from __future__ import with_statement
-
import time
+import textwrap
import threading
import collections
@@ -21,26 +20,27 @@ from ._tango import StdStringVector, DbData, DbDatum, AttributeInfo
from ._tango import AttributeInfoEx, AttributeInfoList, AttributeInfoListEx
from ._tango import DeviceProxy, __CallBackAutoDie, __CallBackPushEvent
from ._tango import EventType, DevFailed, Except, ExtractAs, GreenMode
-from ._tango import constants
+from ._tango import PipeInfo, PipeInfoList, constants
+from ._tango import CmdArgType, DevState
-from .utils import is_pure_str, is_non_str_seq, is_integer
+from .utils import TO_TANGO_TYPE, scalar_to_array_type
+from .utils import is_pure_str, is_non_str_seq, is_integer, is_number
from .utils import seq_2_StdStringVector, StdStringVector_2_seq
from .utils import seq_2_DbData, DbData_2_dict
from .utils import document_method as __document_method
from .utils import dir2
-from .green import result, submit, green, green_cb
-from .green import get_green_mode, get_event_loop, get_wait_default_value
-
+from .green import green, green_callback
+from .green import get_green_mode
__all__ = ["device_proxy_init", "get_device_proxy"]
__docformat__ = "restructuredtext"
-
_UNSUBSCRIBE_LIFETIME = 60
+@green(consume_green_mode=False)
def get_device_proxy(*args, **kwargs):
"""get_device_proxy(self, dev_name, green_mode=None, wait=True, timeout=True) -> DeviceProxy
get_device_proxy(self, dev_name, need_check_acc, green_mode=None, wait=True, timeout=None) -> DeviceProxy
@@ -95,17 +95,7 @@ def get_device_proxy(*args, **kwargs):
New in PyTango 8.1.0
"""
- # we cannot use the green wrapper because it consumes the green_mode and we
- # want to forward it to the DeviceProxy constructor
- green_mode = kwargs.get('green_mode', get_green_mode())
- wait = kwargs.pop('wait', get_wait_default_value(green_mode))
- timeout = kwargs.pop('timeout', None)
-
- # make sure the event loop is initialized
- get_event_loop(green_mode)
-
- d = submit(green_mode, DeviceProxy, *args, **kwargs)
- return result(d, green_mode, wait=wait, timeout=timeout)
+ return DeviceProxy(*args, **kwargs)
class __TangoInfo(object):
@@ -118,21 +108,25 @@ class __TangoInfo(object):
self.server_id = 'Unknown'
self.server_version = 1
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# 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 __check_read_pipe(dev_pipe):
if dev_pipe.has_failed:
raise DevFailed(*dev_pipe.get_err_stack())
return dev_pipe
+
def __init_device_proxy_internals(proxy):
if proxy.__dict__.get('_initialized', False):
return
@@ -142,6 +136,7 @@ def __init_device_proxy_internals(proxy):
proxy.__dict__['_executors'] = executors
proxy.__dict__['_pending_unsubscribe'] = {}
+
def __DeviceProxy__get_cmd_cache(self):
try:
ret = self.__dict__['__cmd_cache']
@@ -149,6 +144,7 @@ def __DeviceProxy__get_cmd_cache(self):
self.__dict__['__cmd_cache'] = ret = {}
return ret
+
def __DeviceProxy__get_attr_cache(self):
try:
ret = self.__dict__['__attr_cache']
@@ -156,6 +152,7 @@ def __DeviceProxy__get_attr_cache(self):
self.__dict__['__attr_cache'] = ret = ()
return ret
+
def __DeviceProxy__get_pipe_cache(self):
try:
ret = self.__dict__['__pipe_cache']
@@ -163,6 +160,7 @@ def __DeviceProxy__get_pipe_cache(self):
self.__dict__['__pipe_cache'] = ret = ()
return ret
+
def __DeviceProxy__init__(self, *args, **kwargs):
__init_device_proxy_internals(self)
self._green_mode = kwargs.pop('green_mode', None)
@@ -171,6 +169,7 @@ def __DeviceProxy__init__(self, *args, **kwargs):
self._executors[GreenMode.Asyncio] = kwargs.pop('asyncio_executor', None)
return DeviceProxy.__init_orig__(self, *args, **kwargs)
+
def __DeviceProxy__get_green_mode(self):
"""Returns the green mode in use by this DeviceProxy.
@@ -188,6 +187,7 @@ def __DeviceProxy__get_green_mode(self):
gm = get_green_mode()
return gm
+
def __DeviceProxy__set_green_mode(self, green_mode=None):
"""Sets the green mode to be used by this DeviceProxy
Setting it to None means use the global PyTango green mode
@@ -212,21 +212,27 @@ def __DeviceProxy__refresh_cmd_cache(self):
cmd_cache[n] = cmd, doc
self.__dict__['__cmd_cache'] = cmd_cache
+
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__refresh_pipe_cache(self):
pipe_cache = [pipe_name.lower() for pipe_name in self.get_pipe_list()]
self.__dict__['__pipe_cache'] = pipe_cache
+
def __get_command_func(dp, cmd_info, name):
_, doc = cmd_info
+
def f(*args, **kwds):
return dp.command_inout(name, *args, **kwds)
+
f.__doc__ = doc
return f
+
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
@@ -265,7 +271,7 @@ def __DeviceProxy__getattr(self, name):
try:
self.__refresh_pipe_cache()
- except Exception as e:
+ except Exception:
pass
if name_l in self.__get_pipe_cache():
@@ -273,6 +279,7 @@ def __DeviceProxy__getattr(self, name):
raise AttributeError(name)
+
def __DeviceProxy__setattr(self, name, value):
name_l = name.lower()
@@ -352,13 +359,6 @@ def __DeviceProxy__read_attribute(self, value, extract_as=ExtractAs.Numpy):
return __check_read_attribute(self._read_attribute(value, extract_as))
-# def __DeviceProxy__read_attribute(self, value, extract_as=ExtractAs.Numpy,
-# green_mode=None, wait=True, timeout=None):
-# green_mode, submit = submitable(green_mode)
-# result = submit(__DeviceProxy__read_attribute_raw, self, value, extract_as=extract_as)
-# return get_result(result, green_mode, wait=wait, timeout=timeout)
-
-
def __DeviceProxy__read_attributes_asynch(self, attr_names, cb=None,
extract_as=ExtractAs.Numpy):
"""
@@ -556,7 +556,8 @@ def __DeviceProxy__get_property(self, propname, value=None):
if is_pure_str(propname[0]):
new_propname = StdStringVector()
- for i in propname: new_propname.append(i)
+ for i in propname:
+ new_propname.append(i)
new_value = value
if new_value is None:
new_value = DbData()
@@ -564,7 +565,8 @@ def __DeviceProxy__get_property(self, propname, value=None):
return DbData_2_dict(new_value)
elif isinstance(propname[0], DbDatum):
new_value = DbData()
- for i in propname: new_value.append(i)
+ for i in propname:
+ new_value.append(i)
self._get_property(new_value)
return DbData_2_dict(new_value)
@@ -618,8 +620,9 @@ def __DeviceProxy__put_property(self, value):
new_value.append(db_datum)
value = new_value
else:
- raise TypeError('value must be a tango.DbDatum, tango.DbData,'\
- 'a sequence<DbDatum> or a dictionary')
+ raise TypeError(
+ 'Value must be a tango.DbDatum, tango.DbData, '
+ 'a sequence<DbDatum> or a dictionary')
return self._put_property(value)
@@ -655,7 +658,7 @@ def __DeviceProxy__delete_property(self, value):
DevFailed from device (DB_SQLError)
"""
if isinstance(value, DbData) or isinstance(value, StdStringVector) or \
- is_pure_str(value):
+ is_pure_str(value):
new_value = value
elif isinstance(value, DbDatum):
new_value = DbData()
@@ -675,8 +678,9 @@ def __DeviceProxy__delete_property(self, value):
else:
new_value.append(DbDatum(k))
else:
- raise TypeError('value must be a string, tango.DbDatum, '\
- 'tango.DbData, a sequence or a dictionary')
+ raise TypeError(
+ 'Value must be a string, tango.DbDatum, '
+ 'tango.DbData, a sequence or a dictionary')
return self._delete_property(new_value)
@@ -723,6 +727,7 @@ def __DeviceProxy__get_property_list(self, filter, array=None):
raise TypeError('array must be a mutable sequence<string>')
+
def __DeviceProxy__get_attribute_config(self, value):
"""
get_attribute_config( self, name) -> AttributeInfoEx
@@ -960,18 +965,22 @@ def __DeviceProxy__set_attribute_config(self, value):
elif isinstance(value, AttributeInfoListEx):
v = value
elif isinstance(value, collections.Sequence):
- if not len(value): return
+ 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)
+ 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')
+ raise TypeError(
+ 'Value must be a AttributeInfo, AttributeInfoEx, '
+ 'sequence<AttributeInfo> or sequence<AttributeInfoEx')
return self._set_attribute_config(v)
@@ -1011,13 +1020,13 @@ def __DeviceProxy__set_pipe_config(self, value):
if isinstance(value[0], PipeInfo):
v = PipeInfoList()
else:
- raise TypeError('value must be a PipeInfo or a ' \
- 'sequence<PipeInfo>')
+ raise TypeError(
+ 'Value must be a PipeInfo or a sequence<PipeInfo>')
for i in value:
v.append(i)
else:
- raise TypeError('value must be a PipeInfo or a ' \
- 'sequence<PipeInfo>')
+ raise TypeError(
+ 'Value must be a PipeInfo or a sequence<PipeInfo>')
return self._set_pipe_config(v)
@@ -1042,9 +1051,37 @@ def __DeviceProxy__get_event_map(self):
return self._subscribed_events
-def __DeviceProxy__subscribe_event (self, attr_name, event_type, cb_or_queuesize, filters=[], stateless=False, extract_as=ExtractAs.Numpy):
+def __DeviceProxy__subscribe_event(self, *args, **kwargs):
"""
- subscribe_event(self, attr_name, event, callback, filters=[], stateless=False, extract_as=Numpy) -> int
+ subscribe_event(event_type, cb, stateless=False, green_mode=None) -> 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.
+ This method is currently used device interface change events only.
+
+ Parameters :
+ - event_type: (EventType) Is the event reason and must be on the enumerated values:
+ * EventType.INTERFACE_CHANGE_EVENT
+ - callback : (callable) Is any callable object or an object with a
+ callable "push_event" method.
+ - 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
+ - green_mode : the corresponding green mode (default is GreenMode.Synchronous)
+
+ Return : An event id which has to be specified when unsubscribing
+ from this event.
+
+ Throws : EventSystemFailed
+
+
+ subscribe_event(self, attr_name, event, callback, filters=[], stateless=False, extract_as=Numpy, green_mode=None) -> int
The client call to subscribe for event reception in the push model.
The client implements a callback method which is triggered when the
@@ -1078,6 +1115,7 @@ def __DeviceProxy__subscribe_event (self, attr_name, event_type, cb_or_queuesize
subscription retry, a callback is executed which contains
the corresponding exception
- extract_as : (ExtractAs)
+ - green_mode : the corresponding green mode (default is GreenMode.Synchronous)
Return : An event id which has to be specified when unsubscribing
from this event.
@@ -1085,11 +1123,12 @@ def __DeviceProxy__subscribe_event (self, attr_name, event_type, cb_or_queuesize
Throws : EventSystemFailed
- subscribe_event(self, attr_name, event, queuesize, filters=[], stateless=False ) -> int
+ subscribe_event(self, attr_name, event, queuesize, filters=[], stateless=False, green_mode=None) -> 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:
@@ -1106,32 +1145,91 @@ def __DeviceProxy__subscribe_event (self, attr_name, event_type, cb_or_queuesize
All other parameters are similar to the descriptions given in the
other subscribe_event() version.
"""
+ # First argument is the event type
+ if args and isinstance(args[0], int):
+ return __DeviceProxy__subscribe_event_global(self, *args, **kwargs)
+ # First argument is the attribute name
+ else:
+ return __DeviceProxy__subscribe_event_attrib(self, *args, **kwargs)
+
+
+def __DeviceProxy__subscribe_event_global(self, event_type, cb,
+ stateless=False, green_mode=None):
+
+ if event_type != EventType.INTERFACE_CHANGE_EVENT:
+ raise TypeError("This method is only for Interface Change Events")
+ else:
+ if isinstance(cb, collections.Callable):
+ cbfn = __CallBackPushEvent()
+ cbfn.push_event = green_callback(
+ cb, obj=self, green_mode=green_mode)
+ elif hasattr(cb, "push_event") and isinstance(
+ cb.push_event, collections.Callable):
+ cbfn = __CallBackPushEvent()
+ cbfn.push_event = green_callback(
+ cb.push_event, obj=self, green_mode=green_mode)
+ else:
+ raise TypeError(
+ "Parameter cb should be a callable object or "
+ "an object with a 'push_event' method.")
+
+ event_id = self.__subscribe_event(event_type, cbfn, stateless)
+
+ with self.__get_event_map_lock():
+ se = self.__get_event_map()
+ evt_data = se.get(event_id)
+ if evt_data is not None:
+ # Raise exception
+ desc = textwrap.dedent("""\
+ Internal PyTango error:
+ %s.subscribe_event(%s) already has key %d assigned to (%s, %s)
+ Please report error to PyTango""")
+ desc %= self, event_type, event_id, evt_data[2], evt_data[1]
+ Except.throw_exception(
+ "Py_InternalError", desc, "DeviceProxy.subscribe_event")
+ se[event_id] = (cbfn, event_type, "dummy")
+ return event_id
+
+
+def __DeviceProxy__subscribe_event_attrib(self, attr_name, event_type,
+ cb_or_queuesize,
+ filters=[], stateless=False,
+ extract_as=ExtractAs.Numpy,
+ green_mode=None):
if isinstance(cb_or_queuesize, collections.Callable):
cb = __CallBackPushEvent()
- cb.push_event = green_cb(cb_or_queuesize, self.get_green_mode())
- elif hasattr(cb_or_queuesize, "push_event") and isinstance(cb_or_queuesize.push_event, collections.Callable):
+ cb.push_event = green_callback(
+ cb_or_queuesize, obj=self, green_mode=green_mode)
+ elif hasattr(cb_or_queuesize, "push_event") and \
+ isinstance(cb_or_queuesize.push_event, collections.Callable):
cb = __CallBackPushEvent()
- cb.push_event = green_cb(cb_or_queuesize.push_event, self.get_green_mode())
+ cb.push_event = green_callback(
+ cb_or_queuesize.push_event, obj=self, green_mode=green_mode)
elif is_integer(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.")
+ 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)
+ event_id = self.__subscribe_event(
+ attr_name, event_type, cb, filters, stateless, extract_as)
with self.__get_event_map_lock():
se = self.__get_event_map()
evt_data = se.get(event_id)
- if evt_data is not None:
- desc = "Internal PyTango error:\n" \
- "%s.subscribe_event(%s, %s) already has key %d assigned to (%s, %s)\n" \
- "Please report error to PyTango" % \
- (self, attr_name, event_type, event_id, evt_data[2], evt_data[1])
- Except.throw_exception("Py_InternalError", desc, "DeviceProxy.subscribe_event")
- se[event_id] = (cb, event_type, attr_name)
- return event_id
+ if evt_data is None:
+ se[event_id] = (cb, event_type, attr_name)
+ return event_id
+ # Raise exception
+ desc = textwrap.dedent("""\
+ Internal PyTango error:
+ %s.subscribe_event(%s, %s) already has key %d assigned to (%s, %s)
+ Please report error to PyTango""")
+ desc %= self, attr_name, event_type, event_id, evt_data[2], evt_data[1]
+ Except.throw_exception(
+ "Py_InternalError", desc, "DeviceProxy.subscribe_event")
def __DeviceProxy__unsubscribe_event(self, event_id):
@@ -1219,16 +1317,18 @@ def __DeviceProxy__get_events(self, event_id, callback=None, extract_as=ExtractA
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 ):
+ 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)
+ elif event_type in (EventType.PIPE_EVENT,):
+ return self.__get_pipe_events(event_id, extract_as)
else:
assert (False)
raise ValueError("Unknown event_type: " + str(event_type))
@@ -1241,7 +1341,8 @@ def __DeviceProxy__get_events(self, event_id, callback=None, extract_as=ExtractA
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.")
+ raise TypeError(
+ "Parameter 'callback' should be None, a callable object or an object with a 'push_event' method.")
def __DeviceProxy___get_info_(self):
@@ -1259,18 +1360,92 @@ def __DeviceProxy__str(self):
return "%s(%s)" % (info.dev_class, self.dev_name())
-def __DeviceProxy__str(self):
- info = self._get_info_()
- return "%s(%s)" % (info.dev_class, self.dev_name())
-
-
def __DeviceProxy__read_pipe(self, pipe_name, extract_as=ExtractAs.Numpy):
r = self.__read_pipe(pipe_name)
return r.extract(extract_as)
-def __DeviceProxy__write_pipe(*args, **kwargs):
- raise NotImplementedError('writtable pipes not implemented in 9.2.0a')
+def __get_pipe_type_simple(obj):
+ if is_non_str_seq(obj):
+ if len(obj) == 2 and \
+ is_pure_str(obj[0]) and \
+ (is_non_str_seq(obj[1]) or isinstance(obj[1], dict)):
+ tg_type = CmdArgType.DevPipeBlob
+ else:
+ tg_type = __get_pipe_type(obj[0])
+ tg_type = scalar_to_array_type(tg_type)
+ elif is_pure_str(obj):
+ tg_type = CmdArgType.DevString
+ elif isinstance(obj, DevState):
+ tg_type = CmdArgType.DevState
+ elif isinstance(obj, bool):
+ tg_type = CmdArgType.DevBoolean
+ elif is_integer(obj):
+ tg_type = CmdArgType.DevLong64
+ elif is_number(obj):
+ tg_type = CmdArgType.DevDouble
+ else:
+ raise ValueError('Cannot determine object tango type')
+ return tg_type
+
+
+def __get_pipe_type_numpy_support(obj):
+ try:
+ ndim, dtype = obj.ndim, str(obj.dtype)
+ except AttributeError:
+ return __get_pipe_type_simple(obj)
+ if ndim > 1:
+ raise TypeError('cannot translate numpy array with {0} '
+ 'dimensions to tango type'.format(obj.ndim))
+ tg_type = TO_TANGO_TYPE[dtype]
+ if ndim > 0:
+ tg_type = scalar_to_array_type(dtype)
+ return tg_type
+
+
+def __get_tango_type(dtype):
+ if is_non_str_seq(dtype):
+ tg_type = dtype[0]
+ if is_non_str_seq(tg_type):
+ raise TypeError("Pipe doesn't support 2D data")
+ tg_type = TO_TANGO_TYPE[tg_type]
+ tg_type = scalar_to_array_type(tg_type)
+ else:
+ tg_type = TO_TANGO_TYPE[dtype]
+ return tg_type
+
+
+def __get_pipe_type(obj, dtype=None):
+ if dtype is not None:
+ return __get_tango_type(dtype)
+ if constants.NUMPY_SUPPORT:
+ return __get_pipe_type_numpy_support(obj)
+ return __get_pipe_type_simple(obj)
+
+
+def __sanatize_pipe_element(elem):
+ if isinstance(elem, dict):
+ result = dict(elem)
+ else:
+ result = dict(name=elem[0], value=elem[1])
+ result['value'] = value = result.get('value', result.pop('blob', None))
+ result['dtype'] = dtype = __get_pipe_type(value, dtype=result.get('dtype'))
+ if dtype == CmdArgType.DevPipeBlob:
+ result['value'] = value[0], __sanatize_pipe_blob(value[1])
+ return result
+
+
+def __sanatize_pipe_blob(blob):
+ if isinstance(blob, dict):
+ return [__sanatize_pipe_element((k, v)) for k, v in blob.items()]
+ else:
+ return [__sanatize_pipe_element(elem) for elem in blob]
+
+
+def __DeviceProxy__write_pipe(self, *args, **kwargs):
+ pipe_name, (blob_name, blob_data) = args
+ sani_blob_data = __sanatize_pipe_blob(blob_data)
+ self.__write_pipe(pipe_name, blob_name, sani_blob_data)
def __DeviceProxy__read_attributes(self, *args, **kwargs):
@@ -1302,6 +1477,7 @@ def __DeviceProxy__state(self, *args, **kwargs):
"""
return self._state(*args, **kwargs)
+
def __DeviceProxy__status(self, *args, **kwargs):
"""status(self) -> str
@@ -1412,7 +1588,8 @@ def __init_DeviceProxy():
DeviceProxy.__get_event_map = __DeviceProxy__get_event_map
DeviceProxy.__get_event_map_lock = __DeviceProxy__get_event_map_lock
- DeviceProxy.subscribe_event = green(__DeviceProxy__subscribe_event)
+ DeviceProxy.subscribe_event = green(
+ __DeviceProxy__subscribe_event, consume_green_mode=False)
DeviceProxy.unsubscribe_event = green(__DeviceProxy__unsubscribe_event)
DeviceProxy.__unsubscribe_event_all = __DeviceProxy__unsubscribe_event_all
DeviceProxy.get_events = __DeviceProxy__get_events
@@ -1482,9 +1659,9 @@ def __doc_DeviceProxy():
"""
-#-------------------------------------
-# General methods
-#-------------------------------------
+ # ------------------------------------
+ # General methods
+ # ------------------------------------
document_method("info", """
info(self) -> DeviceInfo
@@ -1587,9 +1764,9 @@ def __doc_DeviceProxy():
print(black_box(4))
""")
-#-------------------------------------
-# Device methods
-#-------------------------------------
+ # -------------------------------------
+ # Device methods
+ # -------------------------------------
document_method("get_command_list", """
get_command_list(self) -> sequence<str>
@@ -1652,17 +1829,19 @@ def __doc_DeviceProxy():
is an integer"
""")
-#-------------------------------------
-# Property methods
-#-------------------------------------
+ # ------------------------------------
+ # Property methods
+ # ------------------------------------
+
# get_property -> in code
# put_property -> in code
# delete_property -> in code
# get_property_list -> in code
-#-------------------------------------
-# Attribute methods
-#-------------------------------------
+ # ------------------------------------
+ # Attribute methods
+ # ------------------------------------
+
document_method("get_attribute_list", """
get_attribute_list(self) -> sequence<str>
@@ -1917,9 +2096,9 @@ def __doc_DeviceProxy():
New in PyTango 9.2.0
""")
-#-------------------------------------
-# Pipe methods
-#-------------------------------------
+ # -------------------------------------
+ # Pipe methods
+ # -------------------------------------
document_method("read_pipe", """
read_pipe(self, pipe_name, extract_as=ExtractAs.Numpy, green_mode=None, wait=True, timeout=None) -> tuple
@@ -1957,11 +2136,43 @@ def __doc_DeviceProxy():
New in PyTango 9.2.0
""")
- document_method("write_pipe", """TODO""")
+ document_method("write_pipe", """
+ write_pipe(self, blob, green_mode=None, wait=True, timeout=None)
-#-------------------------------------
-# History methods
-#-------------------------------------
+ Write a *blob* to a single pipe. The *blob* comprises: a tuple with two elements: blob name (string) and blob
+ data (sequence). The blob data consists of a sequence where each element is a dictionary with the
+ following keys:
+
+ - name: blob element name
+ - dtype: tango data type
+ - value: blob element data (str for DevString, etc)
+
+ In case dtype is ``DevPipeBlob``, value is also a *blob*.
+
+ Parameters :
+ - blob : a tuple with two elements: blob name (string) and blob
+ data (sequence).
+ - green_mode : (GreenMode) Defaults to the current DeviceProxy GreenMode.
+ (see :meth:`~tango.DeviceProxy.get_green_mode` and
+ :meth:`~tango.DeviceProxy.set_green_mode`).
+ - wait : (bool) whether or not to wait for result. If green_mode
+ is *Synchronous*, this parameter is ignored as it always
+ waits for the result.
+ Ignored when green_mode is Synchronous (always waits).
+ - timeout : (float) The number of seconds to wait for the result.
+ If None, then there is no limit on the wait time.
+ Ignored when green_mode is Synchronous or wait is False.
+
+ Throws : ConnectionFailed, CommunicationFailed, DevFailed from device
+ TimeoutError (green_mode == Futures) If the future didn't finish executing before the given timeout.
+ Timeout (green_mode == Gevent) If the async result didn't finish executing before the given timeout.
+
+ New in PyTango 9.2.1
+ """)
+
+ # -------------------------------------
+ # History methods
+ # -------------------------------------
document_method("command_history", """
command_history(self, cmd_name, depth) -> sequence<DeviceDataHistory>
@@ -1994,9 +2205,9 @@ def __doc_DeviceProxy():
CommunicationFailed, DevFailed from device
""")
-#-------------------------------------
-# Polling administration methods
-#-------------------------------------
+ # -------------------------------------
+ # Polling administration methods
+ # -------------------------------------
document_method("polling_status", """
polling_status(self) -> sequence<str>
@@ -2098,9 +2309,9 @@ def __doc_DeviceProxy():
Return : None
""")
-#-------------------------------------
-# Asynchronous methods
-#-------------------------------------
+ # -------------------------------------
+ # Asynchronous methods
+ # -------------------------------------
# read_attribute_asynch -> in code
# read_attributes_asynch -> in code
@@ -2198,9 +2409,9 @@ def __doc_DeviceProxy():
New in PyTango 7.0.0
""")
-#-------------------------------------
-# Logging administration methods
-#-------------------------------------
+ # ------------------------------------
+ # Logging administration methods
+ # ------------------------------------
document_method("add_logging_target", """
add_logging_target(self, target_type_target_name) -> None
@@ -2300,9 +2511,9 @@ def __doc_DeviceProxy():
New in PyTango 7.0.0
""")
-#-------------------------------------
-# Event methods
-#-------------------------------------
+ # ------------------------------------
+ # Event methods
+ # ------------------------------------
# subscribe_event -> in code
# unsubscribe_event -> in code
@@ -2362,9 +2573,9 @@ def __doc_DeviceProxy():
New in PyTango 7.0.0
""")
-#-------------------------------------
-# Locking methods
-#-------------------------------------
+ # ------------------------------------
+ # Locking methods
+ # ------------------------------------
document_method("lock", """
lock(self, (int)lock_validity) -> None
@@ -2487,6 +2698,7 @@ def __doc_DeviceProxy():
New in PyTango 7.0.0
""")
+
def device_proxy_init(doc=True):
__init_DeviceProxy()
if doc:
diff --git a/tango/device_server.py b/tango/device_server.py
index ec4e385..359d613 100644
--- a/tango/device_server.py
+++ b/tango/device_server.py
@@ -30,7 +30,6 @@ from .attr_data import AttrData
from .log4tango import TangoStream
-
__docformat__ = "restructuredtext"
__all__ = ["ChangeEventProp", "PeriodicEventProp",
@@ -71,6 +70,7 @@ class ChangeEventProp(object):
self.abs_change = ''
self.extensions = []
+
class PeriodicEventProp(object):
"""This class represents the python interface for the Tango IDL object
PeriodicEventProp."""
@@ -295,7 +295,7 @@ def __DeviceImpl__get_device_properties(self, ds_class=None):
for prop_name in self.device_property_list:
setattr(self, prop_name, self.prop_util.get_property_values(prop_name, self.device_property_list))
except DevFailed as df:
- print(80*"-")
+ print(80 * "-")
print(df)
raise df
@@ -318,7 +318,8 @@ def __DeviceImpl__add_attribute(self, attr, r_meth=None, w_meth=None, is_allo_me
Return : (Attr) the newly created attribute.
- Throws : DevFailed"""
+ Throws : DevFailed
+ """
attr_data = None
if isinstance(attr, AttrData):
@@ -363,8 +364,7 @@ def __DeviceImpl__add_attribute(self, attr, r_meth=None, w_meth=None, is_allo_me
def __DeviceImpl__remove_attribute(self, attr_name):
- """
- remove_attribute(self, attr_name) -> None
+ """remove_attribute(self, attr_name) -> None
Remove one attribute from the device attribute list.
@@ -373,7 +373,8 @@ def __DeviceImpl__remove_attribute(self, attr_name):
Return : None
- Throws : DevFailed"""
+ Throws : DevFailed
+ """
try:
# Call this method in a try/except in case remove_attribute
# is called during the DS shutdown sequence
@@ -415,6 +416,67 @@ def __DeviceImpl___remove_attr_meth(self, attr_name):
cl.dyn_att_added_methods.remove(attr_name)
+def __DeviceImpl__add_command(self, cmd, device_level=True):
+ """add_command(self, cmd, level=TANGO::OPERATOR) -> cmd
+
+ Add a new command to the device command list.
+
+ Parameters :
+ - cmd : the new command to be added to the list
+ - device_level : Set this flag to true if the command must be added
+ for only this device
+
+ Return : Command
+
+ Throws : DevFailed
+ """
+ add_name_in_list = False # This flag is always False, what use is it?
+ try:
+ config = dict(cmd.__tango_command__[1][2])
+ if config and ("Display level" in config):
+ disp_level = config["Display level"]
+ else:
+ disp_level = DispLevel.OPERATOR
+ self._add_command(cmd.__name__, cmd.__tango_command__[1], disp_level,
+ device_level)
+ if add_name_in_list:
+ cl = self.get_device_class()
+ cl.dyn_cmd_added_methods.append(cmd.__name__)
+ except:
+ if add_name_in_list:
+ self._remove_cmd(cmd.__name__)
+ raise
+ return cmd
+
+
+def __DeviceImpl__remove_command(self, cmd_name, free_it=False, clean_db=True):
+ """
+ remove_command(self, attr_name) -> None
+
+ Remove one command from the device command list.
+
+ Parameters :
+ - cmd_name : (str) command name to be removed from the list
+ - free_it : Boolean set to true if the command object must be freed.
+ - clean_db : Clean command related information (included polling info
+ if the command is polled) from database.
+ Return : None
+
+ Throws : DevFailed
+ """
+ try:
+ # Call this method in a try/except in case remove
+ # is called during the DS shutdown sequence
+ cl = self.get_device_class()
+ except:
+ return
+
+ if cl.dyn_cmd_added_methods.count(cmd_name) != 0:
+ cl.dyn_cmd_added_methods.remove(cmd_name)
+
+ self._remove_command(cmd_name, free_it, clean_db)
+
+
def __DeviceImpl__debug_stream(self, msg, *args):
"""
debug_stream(self, msg, *args) -> None
@@ -448,6 +510,7 @@ def __DeviceImpl__info_stream(self, msg, *args):
"""
self.__info_stream(msg % args)
+
def __DeviceImpl__warn_stream(self, msg, *args):
"""
warn_stream(self, msg, *args) -> None
@@ -464,6 +527,7 @@ def __DeviceImpl__warn_stream(self, msg, *args):
"""
self.__warn_stream(msg % args)
+
def __DeviceImpl__error_stream(self, msg, *args):
"""
error_stream(self, msg, *args) -> None
@@ -544,6 +608,8 @@ def __init_DeviceImpl():
DeviceImpl.add_attribute = __DeviceImpl__add_attribute
DeviceImpl.remove_attribute = __DeviceImpl__remove_attribute
DeviceImpl._remove_attr_meth = __DeviceImpl___remove_attr_meth
+ DeviceImpl.add_command = __DeviceImpl__add_command
+ DeviceImpl.remove_command = __DeviceImpl__remove_command
DeviceImpl.__str__ = __DeviceImpl__str
DeviceImpl.__repr__ = __DeviceImpl__str
DeviceImpl.debug_stream = __DeviceImpl__debug_stream
@@ -749,7 +815,7 @@ def __doc_DeviceImpl():
Parameters : None
Return : (DevState) the device's previous state
- """ )
+ """)
document_method("get_name", """
get_name(self) -> (str)
@@ -999,6 +1065,23 @@ def __doc_DeviceImpl():
Throws : DevFailed If the attribute name is unknown.
""")
+ document_method("push_pipe_event", """
+ push_pipe_event(self, pipe_name, except) -> None
+ push_pipe_event(self, pipe_name, blob, reuse_it) -> None
+ push_pipe_event(self, pipe_name, blob, timeval, reuse_it) -> None
+
+ Push a pipe event for the given blob.
+
+ Parameters :
+ - pipe_name : (str) pipe name
+ - blob : (DevicePipeBlob) the blob data
+ Return : None
+
+ Throws : DevFailed If the pipe name is unknown.
+
+ New in PyTango 9.2.2
+ """)
+
document_method("get_logger", """
get_logger(self) -> Logger
@@ -1243,6 +1326,17 @@ def __doc_DeviceImpl():
New in PyTango 7.2.1
""")
+ document_method("push_pipe_event", """
+ push_pipe_event(self, blob) -> None
+
+ Push an pipe event.
+
+ Parameters : the blob which pipe event will be send.
+ Return : None
+
+ New in PyTango 9.2.2
+ """)
+
document_method("is_there_subscriber", """
is_there_subscriber(self, att_name, event_type) -> bool
@@ -1872,19 +1966,19 @@ def __doc_WAttribute():
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("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
@@ -1898,6 +1992,7 @@ def __doc_WAttribute():
Return : (obj) the attribute write value.
""")
+
def __doc_MultiClassAttribute():
def document_method(method_name, desc, append=True):
return __document_method(MultiClassAttribute, method_name, desc, append)
@@ -1948,6 +2043,7 @@ def __doc_MultiClassAttribute():
New in PyTango 7.2.1
""")
+
def __doc_MultiAttribute():
def document_method(method_name, desc, append=True):
return __document_method(MultiAttribute, method_name, desc, append)
@@ -2083,6 +2179,7 @@ def __doc_MultiAttribute():
New in PyTango 7.2.1
""")
+
def __doc_Attr():
def document_method(method_name, desc, append=True):
return __document_method(Attr, method_name, desc, append)
@@ -2382,6 +2479,7 @@ def __doc_Attr():
Return : None
""")
+
def __doc_UserDefaultAttrProp():
def document_method(method_name, desc, append=True):
return __document_method(UserDefaultAttrProp, method_name, desc, append)
diff --git a/tango/encoded_attribute.py b/tango/encoded_attribute.py
index 6187ea4..92fc275 100644
--- a/tango/encoded_attribute.py
+++ b/tango/encoded_attribute.py
@@ -17,8 +17,6 @@ __all__ = ["encoded_attribute_init"]
__docformat__ = "restructuredtext"
-import collections
-
from ._tango import EncodedAttribute, ExtractAs, _ImageFormat
from ._tango import constants
@@ -27,18 +25,20 @@ from .utils import is_pure_str, is_seq
if constants.NUMPY_SUPPORT:
try:
import numpy
+
np = numpy
except:
np = None
else:
np = None
-_allowed_extract = ExtractAs.Numpy, ExtractAs.String, ExtractAs.Tuple, \
- ExtractAs.List
+_allowed_extract = (
+ ExtractAs.Numpy, ExtractAs.String, ExtractAs.Tuple, ExtractAs.List)
+
def __EncodedAttribute_encode_jpeg_gray8(self, gray8, width=0, height=0, quality=100.0):
"""Encode a 8 bit grayscale image as JPEG format
-
+
:param gray8: an object containning image information
:type gray8: :py:obj:`str` or :class:`numpy.ndarray` or seq< seq<element> >
:param width: image width. **MUST** be given if gray8 is a string or
@@ -51,19 +51,19 @@ def __EncodedAttribute_encode_jpeg_gray8(self, gray8, width=0, height=0, quality
:type height: :py:obj:`int`
:param quality: Quality of JPEG (0=poor quality 100=max quality) (default is 100.0)
:type quality: :py:obj:`float`
-
+
.. note::
When :class:`numpy.ndarray` is given:
-
+
- gray8 **MUST** be CONTIGUOUS, ALIGNED
- if gray8.ndims != 2, width and height **MUST** be given and
gray8.nbytes **MUST** match width*height
- if gray8.ndims == 2, gray8.itemsize **MUST** be 1 (typically,
gray8.dtype is one of `numpy.dtype.byte`, `numpy.dtype.ubyte`,
`numpy.dtype.int8` or `numpy.dtype.uint8`)
-
+
Example::
-
+
def read_myattr(self, attr):
enc = tango.EncodedAttribute()
data = numpy.arange(100, dtype=numpy.byte)
@@ -73,9 +73,10 @@ def __EncodedAttribute_encode_jpeg_gray8(self, gray8, width=0, height=0, quality
"""
self._generic_encode_gray8(gray8, width=width, height=height, quality=quality, format=_ImageFormat.JpegImage)
+
def __EncodedAttribute_encode_gray8(self, gray8, width=0, height=0):
"""Encode a 8 bit grayscale image (no compression)
-
+
:param gray8: an object containning image information
:type gray8: :py:obj:`str` or :class:`numpy.ndarray` or seq< seq<element> >
:param width: image width. **MUST** be given if gray8 is a string or
@@ -86,19 +87,19 @@ def __EncodedAttribute_encode_gray8(self, gray8, width=0, height=0):
or if it is a :class:`numpy.ndarray` with ndims != 2.
Otherwise it is calculated internally.
:type height: :py:obj:`int`
-
+
.. note::
When :class:`numpy.ndarray` is given:
-
+
- gray8 **MUST** be CONTIGUOUS, ALIGNED
- if gray8.ndims != 2, width and height **MUST** be given and
gray8.nbytes **MUST** match width*height
- if gray8.ndims == 2, gray8.itemsize **MUST** be 1 (typically,
gray8.dtype is one of `numpy.dtype.byte`, `numpy.dtype.ubyte`,
`numpy.dtype.int8` or `numpy.dtype.uint8`)
-
+
Example::
-
+
def read_myattr(self, attr):
enc = tango.EncodedAttribute()
data = numpy.arange(100, dtype=numpy.byte)
@@ -108,6 +109,7 @@ def __EncodedAttribute_encode_gray8(self, gray8, width=0, height=0):
"""
self._generic_encode_gray8(gray8, width=width, height=height, format=_ImageFormat.RawImage)
+
def __EncodedAttribute_generic_encode_gray8(self, gray8, width=0, height=0, quality=0, format=_ImageFormat.RawImage):
"""Internal usage only"""
if not is_seq(gray8):
@@ -130,10 +132,10 @@ def __EncodedAttribute_generic_encode_gray8(self, gray8, width=0, height=0, qual
else:
if gray8.itemsize != 1:
raise TypeError("Expected numpy array with itemsize == 1")
- if gray8.flags.c_contiguous != True:
+ if not gray8.flags.c_contiguous:
raise TypeError("Currently, only contiguous, aligned numpy arrays "
"are supported")
- if gray8.flags.aligned != True:
+ if not gray8.flags.aligned:
raise TypeError("Currently, only contiguous, aligned numpy arrays "
"are supported")
@@ -153,9 +155,10 @@ def __EncodedAttribute_generic_encode_gray8(self, gray8, width=0, height=0, qual
elif format == _ImageFormat.JpegImage:
self._encode_jpeg_gray8(gray8, width, height, quality)
+
def __EncodedAttribute_encode_gray16(self, gray16, width=0, height=0):
"""Encode a 16 bit grayscale image (no compression)
-
+
:param gray16: an object containning image information
:type gray16: :py:obj:`str` or :py:obj:`buffer` or :class:`numpy.ndarray` or seq< seq<element> >
:param width: image width. **MUST** be given if gray16 is a string or
@@ -166,19 +169,19 @@ def __EncodedAttribute_encode_gray16(self, gray16, width=0, height=0):
or if it is a :class:`numpy.ndarray` with ndims != 2.
Otherwise it is calculated internally.
:type height: :py:obj:`int`
-
+
.. note::
When :class:`numpy.ndarray` is given:
-
+
- gray16 **MUST** be CONTIGUOUS, ALIGNED
- if gray16.ndims != 2, width and height **MUST** be given and
gray16.nbytes/2 **MUST** match width*height
- if gray16.ndims == 2, gray16.itemsize **MUST** be 2 (typically,
gray16.dtype is one of `numpy.dtype.int16`, `numpy.dtype.uint16`,
`numpy.dtype.short` or `numpy.dtype.ushort`)
-
+
Example::
-
+
def read_myattr(self, attr):
enc = tango.EncodedAttribute()
data = numpy.arange(100, dtype=numpy.int16)
@@ -196,7 +199,6 @@ def __EncodedAttribute_encode_gray16(self, gray16, width=0, height=0):
raise ValueError("When giving a string as data, you must also "
"supply width and height")
-
if np and isinstance(gray16, np.ndarray):
if gray16.ndim != 2:
if not width or not height:
@@ -207,10 +209,10 @@ def __EncodedAttribute_encode_gray16(self, gray16, width=0, height=0):
else:
if gray16.itemsize != 2:
raise TypeError("Expected numpy array with itemsize == 2")
- if gray16.flags.c_contiguous != True:
+ if not gray16.flags.c_contiguous:
raise TypeError("Currently, only contiguous, aligned numpy arrays "
"are supported")
- if gray16.flags.aligned != True:
+ if not gray16.flags.aligned:
raise TypeError("Currently, only contiguous, aligned numpy arrays "
"are supported")
@@ -229,9 +231,10 @@ def __EncodedAttribute_encode_gray16(self, gray16, width=0, height=0):
self._encode_gray16(gray16, width, height)
+
def __EncodedAttribute_encode_jpeg_rgb24(self, rgb24, width=0, height=0, quality=100.0):
"""Encode a 24 bit rgb color image as JPEG format.
-
+
:param rgb24: an object containning image information
:type rgb24: :py:obj:`str` or :class:`numpy.ndarray` or seq< seq<element> >
:param width: image width. **MUST** be given if rgb24 is a string or
@@ -244,10 +247,10 @@ def __EncodedAttribute_encode_jpeg_rgb24(self, rgb24, width=0, height=0, quality
:type height: :py:obj:`int`
:param quality: Quality of JPEG (0=poor quality 100=max quality) (default is 100.0)
:type quality: :py:obj:`float`
-
+
.. note::
When :class:`numpy.ndarray` is given:
-
+
- rgb24 **MUST** be CONTIGUOUS, ALIGNED
- if rgb24.ndims != 3, width and height **MUST** be given and
rgb24.nbytes/3 **MUST** match width*height
@@ -255,9 +258,9 @@ def __EncodedAttribute_encode_jpeg_rgb24(self, rgb24, width=0, height=0, quality
rgb24.dtype is one of `numpy.dtype.byte`, `numpy.dtype.ubyte`,
`numpy.dtype.int8` or `numpy.dtype.uint8`) and shape **MUST** be
(height, width, 3)
-
+
Example::
-
+
def read_myattr(self, attr):
enc = tango.EncodedAttribute()
# create an 'image' where each pixel is R=0x01, G=0x01, B=0x01
@@ -267,9 +270,10 @@ def __EncodedAttribute_encode_jpeg_rgb24(self, rgb24, width=0, height=0, quality
"""
self._generic_encode_rgb24(rgb24, width=width, height=height, quality=quality, format=_ImageFormat.JpegImage)
+
def __EncodedAttribute_encode_rgb24(self, rgb24, width=0, height=0):
"""Encode a 24 bit color image (no compression)
-
+
:param rgb24: an object containning image information
:type rgb24: :py:obj:`str` or :class:`numpy.ndarray` or seq< seq<element> >
:param width: image width. **MUST** be given if rgb24 is a string or
@@ -280,10 +284,10 @@ def __EncodedAttribute_encode_rgb24(self, rgb24, width=0, height=0):
or if it is a :class:`numpy.ndarray` with ndims != 3.
Otherwise it is calculated internally.
:type height: :py:obj:`int`
-
+
.. note::
When :class:`numpy.ndarray` is given:
-
+
- rgb24 **MUST** be CONTIGUOUS, ALIGNED
- if rgb24.ndims != 3, width and height **MUST** be given and
rgb24.nbytes/3 **MUST** match width*height
@@ -291,9 +295,9 @@ def __EncodedAttribute_encode_rgb24(self, rgb24, width=0, height=0):
rgb24.dtype is one of `numpy.dtype.byte`, `numpy.dtype.ubyte`,
`numpy.dtype.int8` or `numpy.dtype.uint8`) and shape **MUST** be
(height, width, 3)
-
+
Example::
-
+
def read_myattr(self, attr):
enc = tango.EncodedAttribute()
# create an 'image' where each pixel is R=0x01, G=0x01, B=0x01
@@ -303,6 +307,7 @@ def __EncodedAttribute_encode_rgb24(self, rgb24, width=0, height=0):
"""
self._generic_encode_rgb24(rgb24, width=width, height=height, format=_ImageFormat.RawImage)
+
def __EncodedAttribute_generic_encode_rgb24(self, rgb24, width=0, height=0, quality=0, format=_ImageFormat.RawImage):
"""Internal usage only"""
if not is_seq(rgb24):
@@ -325,10 +330,10 @@ def __EncodedAttribute_generic_encode_rgb24(self, rgb24, width=0, height=0, qual
else:
if rgb24.itemsize != 1:
raise TypeError("Expected numpy array with itemsize == 1")
- if rgb24.flags.c_contiguous != True:
+ if not rgb24.flags.c_contiguous:
raise TypeError("Currently, only contiguous, aligned numpy arrays "
"are supported")
- if rgb24.flags.aligned != True:
+ if not rgb24.flags.aligned:
raise TypeError("Currently, only contiguous, aligned numpy arrays "
"are supported")
@@ -349,9 +354,10 @@ def __EncodedAttribute_generic_encode_rgb24(self, rgb24, width=0, height=0, qual
elif format == _ImageFormat.JpegImage:
self._encode_jpeg_rgb24(rgb24, width, height, quality)
+
def __EncodedAttribute_encode_jpeg_rgb32(self, rgb32, width=0, height=0, quality=100.0):
"""Encode a 32 bit rgb color image as JPEG format.
-
+
:param rgb32: an object containning image information
:type rgb32: :py:obj:`str` or :class:`numpy.ndarray` or seq< seq<element> >
:param width: image width. **MUST** be given if rgb32 is a string or
@@ -362,18 +368,18 @@ def __EncodedAttribute_encode_jpeg_rgb32(self, rgb32, width=0, height=0, quality
or if it is a :class:`numpy.ndarray` with ndims != 2.
Otherwise it is calculated internally.
:type height: :py:obj:`int`
-
+
.. note::
When :class:`numpy.ndarray` is given:
-
+
- rgb32 **MUST** be CONTIGUOUS, ALIGNED
- if rgb32.ndims != 2, width and height **MUST** be given and
rgb32.nbytes/4 **MUST** match width*height
- if rgb32.ndims == 2, rgb32.itemsize **MUST** be 4 (typically,
rgb32.dtype is one of `numpy.dtype.int32`, `numpy.dtype.uint32`)
-
+
Example::
-
+
def read_myattr(self, attr):
enc = tango.EncodedAttribute()
data = numpy.arange(100, dtype=numpy.int32)
@@ -401,10 +407,10 @@ def __EncodedAttribute_encode_jpeg_rgb32(self, rgb32, width=0, height=0, quality
else:
if rgb32.itemsize != 4:
raise TypeError("Expected numpy array with itemsize == 4")
- if rgb32.flags.c_contiguous != True:
+ if not rgb32.flags.c_contiguous:
raise TypeError("Currently, only contiguous, aligned numpy arrays "
"are supported")
- if rgb32.flags.aligned != True:
+ if not rgb32.flags.aligned:
raise TypeError("Currently, only contiguous, aligned numpy arrays "
"are supported")
@@ -426,27 +432,27 @@ def __EncodedAttribute_encode_jpeg_rgb32(self, rgb32, width=0, height=0, quality
def __EncodedAttribute_decode_gray8(self, da, extract_as=ExtractAs.Numpy):
"""Decode a 8 bits grayscale image (JPEG_GRAY8 or GRAY8) and returns a 8 bits gray scale image.
-
+
:param da: :class:`DeviceAttribute` that contains the image
:type da: :class:`DeviceAttribute`
:param extract_as: defaults to ExtractAs.Numpy
:type extract_as: ExtractAs
:return: the decoded data
-
+
- In case String string is choosen as extract method, a tuple is returned:
width<int>, height<int>, buffer<str>
- In case Numpy is choosen as extract method, a :class:`numpy.ndarray` is
returned with ndim=2, shape=(height, width) and dtype=numpy.uint8.
- In case Tuple or List are choosen, a tuple<tuple<int>> or list<list<int>>
is returned.
-
+
.. warning::
- The PyTango calls that return a :class:`DeviceAttribute`
+ The PyTango calls that return a :class:`DeviceAttribute`
(like :meth:`DeviceProxy.read_attribute` or :meth:`DeviceProxy.command_inout`)
- automatically extract the contents by default. This method requires
- that the given :class:`DeviceAttribute` is obtained from a
+ automatically extract the contents by default. This method requires
+ that the given :class:`DeviceAttribute` is obtained from a
call which **DOESN'T** extract the contents. Example::
-
+
dev = tango.DeviceProxy("a/b/c")
da = dev.read_attribute("my_attr", extract_as=tango.ExtractAs.Nothing)
enc = tango.EncodedAttribute()
@@ -459,9 +465,10 @@ def __EncodedAttribute_decode_gray8(self, da, extract_as=ExtractAs.Numpy):
raise TypeError("extract_as must be one of Numpy, String, Tuple, List")
return self._decode_gray8(da, extract_as)
+
def __EncodedAttribute_decode_gray16(self, da, extract_as=ExtractAs.Numpy):
"""Decode a 16 bits grayscale image (GRAY16) and returns a 16 bits gray scale image.
-
+
:param da: :class:`DeviceAttribute` that contains the image
:type da: :class:`DeviceAttribute`
:param extract_as: defaults to ExtractAs.Numpy
@@ -476,12 +483,12 @@ def __EncodedAttribute_decode_gray16(self, da, extract_as=ExtractAs.Numpy):
is returned.
.. warning::
- The PyTango calls that return a :class:`DeviceAttribute`
+ The PyTango calls that return a :class:`DeviceAttribute`
(like :meth:`DeviceProxy.read_attribute` or :meth:`DeviceProxy.command_inout`)
- automatically extract the contents by default. This method requires
- that the given :class:`DeviceAttribute` is obtained from a
+ automatically extract the contents by default. This method requires
+ that the given :class:`DeviceAttribute` is obtained from a
call which **DOESN'T** extract the contents. Example::
-
+
dev = tango.DeviceProxy("a/b/c")
da = dev.read_attribute("my_attr", extract_as=tango.ExtractAs.Nothing)
enc = tango.EncodedAttribute()
@@ -494,9 +501,10 @@ def __EncodedAttribute_decode_gray16(self, da, extract_as=ExtractAs.Numpy):
raise TypeError("extract_as must be one of Numpy, String, Tuple, List")
return self._decode_gray16(da, extract_as)
+
def __EncodedAttribute_decode_rgb32(self, da, extract_as=ExtractAs.Numpy):
"""Decode a color image (JPEG_RGB or RGB24) and returns a 32 bits RGB image.
-
+
:param da: :class:`DeviceAttribute` that contains the image
:type da: :class:`DeviceAttribute`
:param extract_as: defaults to ExtractAs.Numpy
@@ -509,14 +517,14 @@ def __EncodedAttribute_decode_rgb32(self, da, extract_as=ExtractAs.Numpy):
returned with ndim=2, shape=(height, width) and dtype=numpy.uint32.
- In case Tuple or List are choosen, a tuple<tuple<int>> or list<list<int>>
is returned.
-
+
.. warning::
- The PyTango calls that return a :class:`DeviceAttribute`
+ The PyTango calls that return a :class:`DeviceAttribute`
(like :meth:`DeviceProxy.read_attribute` or :meth:`DeviceProxy.command_inout`)
- automatically extract the contents by default. This method requires
- that the given :class:`DeviceAttribute` is obtained from a
+ automatically extract the contents by default. This method requires
+ that the given :class:`DeviceAttribute` is obtained from a
call which **DOESN'T** extract the contents. Example::
-
+
dev = tango.DeviceProxy("a/b/c")
da = dev.read_attribute("my_attr", extract_as=tango.ExtractAs.Nothing)
enc = tango.EncodedAttribute()
@@ -529,6 +537,7 @@ def __EncodedAttribute_decode_rgb32(self, da, extract_as=ExtractAs.Numpy):
raise TypeError("extract_as must be one of Numpy, String, Tuple, List")
return self._decode_rgb32(da, extract_as)
+
def __init_EncodedAttribute():
EncodedAttribute._generic_encode_gray8 = __EncodedAttribute_generic_encode_gray8
EncodedAttribute.encode_gray8 = __EncodedAttribute_encode_gray8
@@ -542,9 +551,11 @@ def __init_EncodedAttribute():
EncodedAttribute.decode_gray16 = __EncodedAttribute_decode_gray16
EncodedAttribute.decode_rgb32 = __EncodedAttribute_decode_rgb32
+
def __doc_EncodedAttribute():
pass
+
def encoded_attribute_init(doc=True):
__init_EncodedAttribute()
if doc:
diff --git a/tango/exception.py b/tango/exception.py
index 5cbc77e..fb01b14 100644
--- a/tango/exception.py
+++ b/tango/exception.py
@@ -20,6 +20,7 @@ __docformat__ = "restructuredtext"
from .utils import document_static_method as __document_static_method
from ._tango import Except, DevError, ErrSeverity
+
def __to_dev_failed(exc_type=None, exc_value=None, traceback=None):
"""to_dev_failed(exc_type, exc_value, traceback) -> tango.DevFailed
@@ -27,25 +28,26 @@ def __to_dev_failed(exc_type=None, exc_value=None, traceback=None):
The exception is created with a single :class:`~tango.DevError`
object. A default value *tango.ErrSeverity.ERR* is defined for
the :class:`~tango.DevError` severity field.
-
+
The parameters are the same as the ones generates by a call to
:func:`sys.exc_info`.
-
+
Parameters :
- type : (class) the exception type of the exception being handled
- value : (object) exception parameter (its associated value or the
second argument to raise, which is always a class instance
if the exception type is a class object)
- traceback : (traceback) traceback object
-
+
Return : (tango.DevFailed) a tango exception object
-
+
New in PyTango 7.2.1"""
try:
Except.throw_python_exception(exc_type, exc_value, traceback)
except Exception as e:
return e
+
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
# DevError pickle
# -~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
@@ -53,43 +55,48 @@ def __to_dev_failed(exc_type=None, exc_value=None, traceback=None):
def __DevError__getinitargs__(self):
return ()
+
def __DevError__getstate__(self):
return self.reason, self.desc, self.origin, int(self.severity)
+
def __DevError__setstate__(self, state):
self.reason = state[0]
self.desc = state[1]
self.origin = state[2]
self.severity = ErrSeverity(state[3])
+
def __init_DevError():
DevError.__getinitargs__ = __DevError__getinitargs__
DevError.__getstate__ = __DevError__getstate__
DevError.__setstate__ = __DevError__setstate__
+
def __init_Except():
Except.to_dev_failed = staticmethod(__to_dev_failed)
+
def __doc_Except():
def document_static_method(method_name, desc, append=True):
return __document_static_method(Except, method_name, desc, append)
-
+
Except.__doc__ = """
A containner for the static methods:
-
+
- throw_exception
- re_throw_exception
- print_exception
- compare_exception"""
-
+
document_static_method("throw_exception", """
throw_exception(reason, desc, origin, sever=tango.ErrSeverity.ERR) -> None
Generate and throw a TANGO DevFailed exception.
- The exception is created with a single :class:`~tango.DevError`
- object. A default value *tango.ErrSeverity.ERR* is defined for
+ The exception is created with a single :class:`~tango.DevError`
+ object. A default value *tango.ErrSeverity.ERR* is defined for
the :class:`~tango.DevError` severity field.
-
+
Parameters :
- reason : (str) The exception :class:`~tango.DevError` object reason field
- desc : (str) The exception :class:`~tango.DevError` object desc field
@@ -97,7 +104,7 @@ def __doc_Except():
- sever : (tango.ErrSeverity) The exception DevError object severity field
Throws : DevFailed
- """ )
+ """)
document_static_method("re_throw_exception", """
re_throw_exception(ex, reason, desc, origin, sever=tango.ErrSeverity.ERR) -> None
@@ -106,7 +113,7 @@ def __doc_Except():
The exception is re-thrown with one more :class:`~tango.DevError` object.
A default value *tango.ErrSeverity.ERR* is defined for the new
:class:`~tango.DevError` severity field.
-
+
Parameters :
- ex : (tango.DevFailed) The :class:`~tango.DevFailed` exception
- reason : (str) The exception :class:`~tango.DevError` object reason field
@@ -115,26 +122,26 @@ def __doc_Except():
- sever : (tango.ErrSeverity) The exception DevError object severity field
Throws : DevFailed
- """ )
-
+ """)
+
document_static_method("print_error_stack", """
print_error_stack(ex) -> None
Print all the details of a TANGO error stack.
-
+
Parameters :
- ex : (tango.DevErrorList) The error stack reference
- """ )
+ """)
document_static_method("print_exception", """
print_exception(ex) -> None
Print all the details of a TANGO exception.
-
+
Parameters :
- ex : (tango.DevFailed) The :class:`~tango.DevFailed` exception
- """ )
-
+ """)
+
document_static_method("throw_python_exception", """
throw_python_exception(type, value, traceback) -> None
@@ -142,10 +149,10 @@ def __doc_Except():
The exception is created with a single :class:`~tango.DevError`
object. A default value *tango.ErrSeverity.ERR* is defined for
the :class:`~tango.DevError` severity field.
-
+
The parameters are the same as the ones generates by a call to
:func:`sys.exc_info`.
-
+
Parameters :
- type : (class) the exception type of the exception being handled
- value : (object) exception parameter (its associated value or the
@@ -154,21 +161,22 @@ def __doc_Except():
- traceback : (traceback) traceback object
Throws : DevFailed
-
+
New in PyTango 7.2.1
- """ )
-
+ """)
+
+
def __doc_DevError():
DevError.__doc__ = """
Structure describing any error resulting from a command execution,
or an attribute query, with following members:
-
+
- reason : (str) reason
- severity : (ErrSeverity) error severty (WARN, ERR, PANIC)
- desc : (str) error description
- origin : (str) Tango server method in which the error happened"""
-
+
def exception_init(doc=True):
__init_Except()
__init_DevError()
diff --git a/tango/futures.py b/tango/futures.py
index d676888..0ceb2ae 100644
--- a/tango/futures.py
+++ b/tango/futures.py
@@ -23,14 +23,15 @@ from tango.attribute_proxy import get_attribute_proxy
def check_requirements():
try:
- import concurrent.futures
+ import concurrent.futures # noqa: F401
except ImportError:
import sys
if sys.version_info[0] < 3:
- raise ImportError("No module named concurrent. You need to " \
- "install the futures backport module to have " \
- "access to PyTango futures green mode")
-
+ raise ImportError(
+ "No module named concurrent. You need to "
+ "install the futures backport module to have "
+ "access to PyTango futures green mode")
+
check_requirements()
@@ -40,20 +41,20 @@ DeviceProxy.__doc__ = """
DeviceProxy(self, dev_name, need_check_acc, wait=True, timeout=True) -> DeviceProxy
Creates a *futures* enabled :class:`~tango.DeviceProxy`.
-
+
The DeviceProxy constructor internally makes some network calls which makes
it *slow*. By using the futures *green mode* you are allowing other
python code to be executed in a cooperative way.
.. note::
The timeout parameter has no relation with the tango device client side
- timeout (gettable by :meth:`~tango.DeviceProxy.get_timeout_millis` and
+ timeout (gettable by :meth:`~tango.DeviceProxy.get_timeout_millis` and
settable through :meth:`~tango.DeviceProxy.set_timeout_millis`)
:param dev_name: the device name or alias
:type dev_name: str
:param need_check_acc: in first version of the function it defaults to True.
- Determines if at creation time of DeviceProxy it
+ Determines if at creation time of DeviceProxy it
should check for channel access (rarely used)
:type need_check_acc: bool
:param wait: whether or not to wait for result of creating a DeviceProxy.
@@ -68,10 +69,10 @@ DeviceProxy.__doc__ = """
else:
:class:`concurrent.futures.Future`
:throws:
- * a *DevFailed* if wait is True and there is an error creating
+ * a *DevFailed* if wait is True and there is an error creating
the device.
* a *concurrent.futures.TimeoutError* if wait is False, timeout is not
- None and the time to create the device has expired.
+ None and the time to create the device has expired.
New in PyTango 8.1.0
"""
@@ -82,7 +83,7 @@ AttributeProxy.__doc__ = """
AttributeProxy(self, device_proxy, attr_name, wait=True, timeout=True) -> AttributeProxy
Creates a *futures* enabled :class:`~tango.AttributeProxy`.
-
+
The AttributeProxy constructor internally makes some network calls which
makes it *slow*. By using the *gevent mode* you are allowing other python
code to be executed in a cooperative way.
@@ -110,7 +111,7 @@ AttributeProxy.__doc__ = """
attribute.
* a *concurrent.futures.TimeoutError* if wait is False, timeout is not
None and the time to create the attribute has expired.
-
+
New in PyTango 8.1.0
"""
diff --git a/tango/futures_executor.py b/tango/futures_executor.py
new file mode 100644
index 0000000..a6dedc2
--- /dev/null
+++ b/tango/futures_executor.py
@@ -0,0 +1,66 @@
+# ------------------------------------------------------------------------------
+# This file is part of PyTango (http://pytango.rtfd.io)
+#
+# Copyright 2006-2012 CELLS / ALBA Synchrotron, Bellaterra, Spain
+# Copyright 2013-2014 European Synchrotron Radiation Facility, Grenoble, France
+#
+# Distributed under the terms of the GNU Lesser General Public License,
+# either version 3 of the License, or (at your option) any later version.
+# See LICENSE.txt for more info.
+# ------------------------------------------------------------------------------
+
+# Future imports
+from __future__ import absolute_import
+
+# Concurrent imports
+from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
+
+# Tango imports
+from .green import AbstractExecutor
+
+__all__ = ["FuturesExecutor", "get_global_executor", "set_global_executor"]
+
+# Global executor
+
+_EXECUTOR = None
+
+
+def get_global_executor():
+ global _EXECUTOR
+ if _EXECUTOR is None:
+ _EXECUTOR = FuturesExecutor()
+ return _EXECUTOR
+
+
+def set_global_executor(executor):
+ global _EXECUTOR
+ _EXECUTOR = executor
+
+
+# Futures executor
+
+class FuturesExecutor(AbstractExecutor):
+ """Futures tango executor"""
+
+ asynchronous = True
+ default_wait = True
+
+ def __init__(self, process=False, max_workers=20):
+ cls = ProcessPoolExecutor if process else ThreadPoolExecutor
+ self.subexecutor = cls(max_workers=max_workers)
+
+ def delegate(self, fn, *args, **kwargs):
+ """Return the given operation as a concurrent future."""
+ return self.subexecutor.submit(fn, *args, **kwargs)
+
+ def access(self, accessor, timeout=None):
+ """Return a result from a single callable."""
+ return accessor.result(timeout=timeout)
+
+ def submit(self, fn, *args, **kwargs):
+ """Submit an operation"""
+ return fn(*args, **kwargs)
+
+ def execute(self, fn, *args, **kwargs):
+ """Execute an operation and return the result."""
+ return fn(*args, **kwargs)
diff --git a/tango/gevent.py b/tango/gevent.py
index 8cfdeac..7d6a844 100644
--- a/tango/gevent.py
+++ b/tango/gevent.py
@@ -13,35 +13,33 @@
:class:`tango.AttributeProxy"""
from __future__ import absolute_import
+from functools import partial
-__all__ = ["DeviceProxy", "AttributeProxy", "check_requirements"]
+from ._tango import GreenMode
+from .device_proxy import get_device_proxy
+from .attribute_proxy import get_attribute_proxy
-from functools import partial
-
-from tango import GreenMode
-from tango.device_proxy import get_device_proxy
-from tango.attribute_proxy import get_attribute_proxy
+__all__ = ["DeviceProxy", "AttributeProxy", "check_requirements"]
def check_requirements():
try:
import gevent
except ImportError:
- raise ImportError("No module named gevent. You need to install " \
- "gevent module to have access to PyTango gevent " \
- "green mode. Consider using the futures green mode " \
+ raise ImportError("No module named gevent. You need to install "
+ "gevent module to have access to PyTango gevent "
+ "green mode. Consider using the futures green mode "
"instead")
import distutils.version
gevent_version = ".".join(map(str, gevent.version_info[:3]))
if distutils.version.StrictVersion(gevent_version) < "1.0":
- raise ImportError("You need gevent >= 1.0. You are using %s. " \
- "Consider using the futures green mode instead" \
+ raise ImportError("You need gevent >= 1.0. You are using %s. "
+ "Consider using the futures green mode instead"
% gevent_version)
-check_requirements()
-
+check_requirements()
DeviceProxy = partial(get_device_proxy, green_mode=GreenMode.Gevent)
DeviceProxy.__doc__ = """
@@ -49,14 +47,14 @@ DeviceProxy.__doc__ = """
DeviceProxy(self, dev_name, need_check_acc, wait=True, timeout=True) -> DeviceProxy
Creates a *gevent* enabled :class:`~tango.DeviceProxy`.
-
+
The DeviceProxy constructor internally makes some network calls which makes
it *slow*. By using the gevent *green mode* you are allowing other python
code to be executed in a cooperative way.
.. note::
The timeout parameter has no relation with the tango device client side
- timeout (gettable by :meth:`~tango.DeviceProxy.get_timeout_millis` and
+ timeout (gettable by :meth:`~tango.DeviceProxy.get_timeout_millis` and
settable through :meth:`~tango.DeviceProxy.set_timeout_millis`)
:param dev_name: the device name or alias
@@ -77,7 +75,7 @@ DeviceProxy.__doc__ = """
else:
:class:`gevent.event.AsynchResult`
:throws:
- * a *DevFailed* if wait is True and there is an error creating
+ * a *DevFailed* if wait is True and there is an error creating
the device.
* a *gevent.timeout.Timeout* if wait is False, timeout is not None and
the time to create the device has expired.
@@ -91,7 +89,7 @@ AttributeProxy.__doc__ = """
AttributeProxy(self, device_proxy, attr_name, wait=True, timeout=True) -> AttributeProxy
Creates a *gevent* enabled :class:`~tango.AttributeProxy`.
-
+
The AttributeProxy constructor internally makes some network calls which
makes it *slow*. By using the *gevent mode* you are allowing other python
code to be executed in a cooperative way.
@@ -119,7 +117,7 @@ AttributeProxy.__doc__ = """
attribute.
* a *gevent.timeout.Timeout* if wait is False, timeout is not None
and the time to create the attribute has expired.
-
+
New in PyTango 8.1.0
"""
diff --git a/tango/gevent_executor.py b/tango/gevent_executor.py
new file mode 100644
index 0000000..02368f1
--- /dev/null
+++ b/tango/gevent_executor.py
@@ -0,0 +1,184 @@
+# ------------------------------------------------------------------------------
+# This file is part of PyTango (http://pytango.rtfd.io)
+#
+# Copyright 2006-2012 CELLS / ALBA Synchrotron, Bellaterra, Spain
+# Copyright 2013-2014 European Synchrotron Radiation Facility, Grenoble, France
+#
+# Distributed under the terms of the GNU Lesser General Public License,
+# either version 3 of the License, or (at your option) any later version.
+# See LICENSE.txt for more info.
+# ------------------------------------------------------------------------------
+
+# Future imports
+from __future__ import absolute_import
+
+# Imports
+import sys
+import six
+import types
+import functools
+
+# Combatibility imports
+try:
+ from threading import get_ident
+except:
+ from threading import _get_ident as get_ident
+
+# Gevent imports
+import gevent.queue
+
+# Tango imports
+from .green import AbstractExecutor
+
+__all__ = ["get_global_executor", "set_global_executor", "GeventExecutor"]
+
+# Global executor
+
+_EXECUTOR = None
+
+
+def get_global_executor():
+ global _EXECUTOR
+ if _EXECUTOR is None:
+ _EXECUTOR = GeventExecutor()
+ return _EXECUTOR
+
+
+def set_global_executor(executor):
+ global _EXECUTOR
+ _EXECUTOR = executor
+
+
+# Patch for gevent threadpool
+
+def get_global_threadpool():
+ """Before gevent-1.1.0, patch the spawn method to propagate exception
+ raised in the loop to the AsyncResult.
+ """
+ threadpool = gevent.get_hub().threadpool
+ if gevent.version_info < (1, 1) and not hasattr(threadpool, '_spawn'):
+ threadpool._spawn = threadpool.spawn
+ threadpool.spawn = types.MethodType(
+ spawn, threadpool, type(threadpool))
+ return threadpool
+
+
+class ExceptionWrapper:
+ def __init__(self, exception, error_string, tb):
+ self.exception = exception
+ self.error_string = error_string
+ self.tb = tb
+
+
+def wrap_errors(func):
+ @functools.wraps(func)
+ def wrapper(*args, **kwargs):
+ try:
+ return func(*args, **kwargs)
+ except:
+ return ExceptionWrapper(*sys.exc_info())
+
+ return wrapper
+
+
+def get_with_exception(result, block=True, timeout=None):
+ result = result._get(block, timeout)
+ if isinstance(result, ExceptionWrapper):
+ # Raise the exception using the caller context
+ six.reraise(result.exception, result.error_string, result.tb)
+ return result
+
+
+def spawn(threadpool, fn, *args, **kwargs):
+ # The gevent threadpool do not raise exception with async results,
+ # we have to wrap it
+ fn = wrap_errors(fn)
+ result = threadpool._spawn(fn, *args, **kwargs)
+ result._get = result.get
+ result.get = types.MethodType(get_with_exception, result, type(result))
+ return result
+
+
+# Gevent task and event loop
+
+class GeventTask:
+ def __init__(self, event, func, *args, **kwargs):
+ self.event = event
+ self.func = func
+ self.args = args
+ self.kwargs = kwargs
+ self.value = None
+ self.exception = None
+
+ def run(self):
+ try:
+ self.value = self.func(*self.args, **self.kwargs)
+ except:
+ self.exception = sys.exc_info()
+ finally:
+ self.event.set()
+
+ def spawn(self):
+ return gevent.spawn(self.run)
+
+ def result(self):
+ self.event.wait()
+ if self.exception:
+ six.reraise(*self.exception)
+ return self.value
+
+
+class GeventLoop:
+ def __init__(self):
+ self.thread_id = get_ident()
+ self.tasks = gevent.queue.Queue()
+ self.loop = gevent.spawn(self.run)
+
+ def run(self):
+ while True:
+ self.tasks.get().spawn()
+
+ def is_gevent_thread(self):
+ return self.thread_id == get_ident()
+
+ def submit(self, func, *args, **kwargs):
+ event = gevent._threading.Event()
+ task = GeventTask(event, func, *args, **kwargs)
+ self.tasks.put_nowait(task)
+ self.tasks.hub.loop.async().send()
+ return task
+
+
+# Gevent executor
+
+class GeventExecutor(AbstractExecutor):
+ """Gevent tango executor"""
+
+ asynchronous = True
+ default_wait = True
+
+ def __init__(self, loop=None, subexecutor=None):
+ if loop is None:
+ loop = GeventLoop()
+ if subexecutor is None:
+ subexecutor = get_global_threadpool()
+ self.loop = loop
+ self.subexecutor = subexecutor
+
+ def delegate(self, fn, *args, **kwargs):
+ """Return the given operation as a gevent future."""
+ return self.subexecutor.spawn(fn, *args, **kwargs)
+
+ def access(self, accessor, timeout=None):
+ """Return a result from an gevent future."""
+ return accessor.get(timeout=timeout)
+
+ def submit(self, fn, *args, **kwargs):
+ return self.loop.submit(fn, *args, **kwargs)
+
+ def execute(self, fn, *args, **kwargs):
+ """Execute an operation and return the result."""
+ if self.loop.is_gevent_thread():
+ return fn(*args, **kwargs)
+ task = self.submit(fn, *args, **kwargs)
+ return task.result()
diff --git a/tango/globals.py b/tango/globals.py
index 497d4f5..e613e49 100644
--- a/tango/globals.py
+++ b/tango/globals.py
@@ -13,11 +13,11 @@
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"]
-
+__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>
@@ -29,48 +29,57 @@ 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
#
@@ -78,7 +87,8 @@ def get_constructed_class_by_class(klass):
def delete_class_list():
global constructed_class
if len(constructed_class) != 0:
- del(constructed_class[:])
+ del (constructed_class[:])
+
#
# A generic class_factory method
@@ -105,4 +115,3 @@ def class_factory():
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/tango/green.py b/tango/green.py
index 909fc29..020c4d7 100644
--- a/tango/green.py
+++ b/tango/green.py
@@ -9,54 +9,25 @@
# See LICENSE.txt for more info.
# -----------------------------------------------------------------------------
-__all__ = [
- "get_green_mode", "set_green_mode",
- "get_executor", "submit", "spawn", "result", "wait",
- "get_synch_executor", "synch_submit", "synch_wait",
- "get_gevent_executor", "gevent_submit", "gevent_wait",
- "get_futures_executor", "futures_submit", "futures_wait",
- "get_asyncio_executor", "asyncio_submit", "asyncio_wait",
- "get_object_submitter", "get_object_waiter", "get_object_green_mode",
- "green", "green_cb", "get_wait_default_value",
- "get_event_loop", "get_gevent_event_loop"]
-
-__docformat__ = "restructuredtext"
-
# Imports
import os
-from functools import wraps, partial
+from functools import wraps
# Tango imports
from ._tango import GreenMode
-# Gevent imports
-from .tango_gevent import get_global_executor as get_gevent_executor
-from .tango_gevent import submit as gevent_submit
-from .tango_gevent import wait as gevent_wait
-from .tango_gevent import get_event_loop as get_gevent_event_loop
-
-# Futures imports
-from .tango_futures import get_global_executor as get_futures_executor
-from .tango_futures import submit as futures_submit
-from .tango_futures import wait as futures_wait
-
-# Asyncio imports
-from .tango_asyncio import get_global_executor as get_asyncio_executor
-from .tango_asyncio import submit as asyncio_submit
-from .tango_asyncio import wait as asyncio_wait
-from .tango_asyncio import get_event_loop as get_asyncio_event_loop
-
+__all__ = ['get_green_mode', 'set_green_mode', 'green', 'green_callback',
+ 'get_executor', 'get_object_executor']
# Handle current green mode
-__default_green_mode = GreenMode.Synchronous
try:
- __current_green_mode = getattr(
+ _CURRENT_GREEN_MODE = getattr(
GreenMode,
os.environ["PYTANGO_GREEN_MODE"].capitalize())
except Exception:
- __current_green_mode = __default_green_mode
+ _CURRENT_GREEN_MODE = GreenMode.Synchronous
def set_green_mode(green_mode=None):
@@ -69,19 +40,11 @@ def set_green_mode(green_mode=None):
:param green_mode: the new global default PyTango green mode
:type green_mode: GreenMode
"""
- global __current_green_mode
- if __current_green_mode == green_mode:
- return
- if green_mode == GreenMode.Gevent:
- # check if we can change to gevent mode
- import tango.gevent
- elif green_mode == GreenMode.Futures:
- # check if we can change to futures mode
- import tango.futures
- elif green_mode == GreenMode.Asyncio:
- # check if we can change to asyncio mode
- import tango.asyncio
- __current_green_mode = green_mode
+ global _CURRENT_GREEN_MODE
+ # Make sure the green mode is available
+ get_executor(green_mode)
+ # Set the green mode
+ _CURRENT_GREEN_MODE = green_mode
def get_green_mode():
@@ -90,192 +53,147 @@ def get_green_mode():
:returns: the current global default PyTango green mode
:rtype: GreenMode
"""
- return __current_green_mode
+ return _CURRENT_GREEN_MODE
-# Synchronous execution
+# Abstract executor class
-class SynchExecutor(object):
- def submit(self, fn, *args, **kwargs):
- return fn(*args, **kwargs)
+class AbstractExecutor(object):
+ asynchronous = NotImplemented
+ default_wait = NotImplemented
-__synch_executor = SynchExecutor()
+ def delegate(self, fn, *args, **kwargs):
+ """Delegate an operation and return an accessor."""
+ if not self.asynchronous:
+ raise ValueError('Not supported in synchronous mode')
+ raise NotImplementedError
+ def access(self, accessor, timeout=None):
+ """Return a result from an accessor."""
+ if not self.asynchronous:
+ raise ValueError('Not supported in synchronous mode')
+ raise NotImplementedError
-def get_synch_executor():
- return __synch_executor
-
-
-def synch_submit(fn, *args, **kwargs):
- return get_synch_executor().submit(fn, *args, **kwargs)
+ def submit(self, fn, *args, **kwargs):
+ """Submit an operation"""
+ if not self.asynchronous:
+ return fn(*args, **kwargs)
+ raise NotImplementedError
+ def execute(self, fn, *args, **kwargs):
+ """Execute an operation and return the result."""
+ if not self.asynchronous:
+ return fn(*args, **kwargs)
+ raise NotImplementedError
-def synch_wait(res, timeout=None):
- return res
+ def run(self, fn, args=(), kwargs={}, wait=None, timeout=None):
+ if wait is None:
+ wait = self.default_wait
+ # Sychronous (no delegation)
+ if not self.asynchronous:
+ if not wait or timeout:
+ raise ValueError('Not supported in synchronous mode')
+ return fn(*args, **kwargs)
+ # Asynchronous delegation
+ accessor = self.delegate(fn, *args, **kwargs)
+ if not wait:
+ return accessor
+ return self.access(accessor, timeout=timeout)
-# Excutor, submitter and waiter mapping
+class SynchronousExecutor(AbstractExecutor):
+ asynchronous = False
+ default_wait = True
-__executor_map = {
- GreenMode.Synchronous: get_synch_executor,
- GreenMode.Futures: get_futures_executor,
- GreenMode.Gevent: get_gevent_executor,
- GreenMode.Asyncio: get_asyncio_executor,
-}
-__submit_map = {
- GreenMode.Synchronous: synch_submit,
- GreenMode.Futures: futures_submit,
- GreenMode.Gevent: gevent_submit,
- GreenMode.Asyncio: asyncio_submit,
-}
+# Default synchronous executor
-__wait_map = {
- GreenMode.Synchronous: synch_wait,
- GreenMode.Futures: futures_wait,
- GreenMode.Gevent: gevent_wait,
- GreenMode.Asyncio: asyncio_wait,
-}
+def get_synchronous_executor():
+ return _SYNCHRONOUS_EXECUTOR
-__event_loop_map = {
- GreenMode.Synchronous: (lambda: None),
- GreenMode.Futures: (lambda: None),
- GreenMode.Gevent: get_gevent_event_loop,
- GreenMode.Asyncio: get_asyncio_event_loop,
-}
+_SYNCHRONOUS_EXECUTOR = SynchronousExecutor()
# Getters
-def get_executor(mode):
- return __executor_map[mode]()
-
-
-def get_submitter(mode):
- return __submit_map[mode]
-
-
-def get_waiter(mode):
- return __wait_map[mode]
-
-
-def get_wait_default_value(mode):
- if mode is None:
- mode = get_green_mode()
- return mode not in (GreenMode.Asyncio,)
-
-
-# Generic submitter/spawner and waiter
-
-def submit(mode, fn, *args, **kwargs):
- return get_submitter(mode)(fn, *args, **kwargs)
-
-spawn = submit
-
-
-def wait_result(ret, green_mode=None, timeout=None):
- if green_mode is None:
- green_mode = get_green_mode()
- return get_waiter(green_mode)(ret, timeout=timeout)
-
-wait = wait_result
-
-
-def result(ret, green_mode=None, wait=True, timeout=None):
- if not wait:
- return ret
- return wait_result(ret, green_mode=green_mode, timeout=timeout)
-
-
-def get_event_loop(mode):
- return __event_loop_map[mode]()
-
-
-# Get object submitter, waiter and green_mode
-
def get_object_green_mode(obj):
if hasattr(obj, "get_green_mode"):
return obj.get_green_mode()
return get_green_mode()
-def get_object_submitter(obj, green_mode=None):
- """Returns the proper submit callable for the given object.
+def get_executor(green_mode=None):
+ if green_mode is None:
+ green_mode = get_green_mode()
+ # Valid green modes
+ if green_mode == GreenMode.Synchronous:
+ return get_synchronous_executor()
+ if green_mode == GreenMode.Gevent:
+ from . import gevent_executor
+ return gevent_executor.get_global_executor()
+ if green_mode == GreenMode.Futures:
+ from . import futures_executor
+ return futures_executor.get_global_executor()
+ if green_mode == GreenMode.Asyncio:
+ from . import asyncio_executor
+ return asyncio_executor.get_global_executor()
+ # Invalid green mode
+ raise TypeError("Not a valid green mode")
+
+
+def get_object_executor(obj, green_mode=None):
+ """Returns the proper executor for the given object.
If the object has *_executors* and *_green_mode* members it returns
the submit callable for the executor corresponding to the green_mode.
- Otherwise it returns the global submit callable for the given green_mode.
+ Otherwise it returns the global executor for the given green_mode.
+
+ Note: *None* is a valid object.
:returns: submit callable"""
# Get green mode
if green_mode is None:
green_mode = get_object_green_mode(obj)
# Get executor
- executors = getattr(obj, "_executors", {})
- executor = executors.get(green_mode, None)
+ executor = None
+ if hasattr(obj, '_executors'):
+ executor = obj._executors.get(green_mode, None)
if executor is None:
executor = get_executor(green_mode)
# Get submitter
- return executor.submit
+ return executor
-def get_object_waiter(obj, green_mode=None):
- """Returns the proper wait callable for the given object.
+# Green modifiers
- If the object has *_executors* and *_green_mode* members it returns
- the wait callable for the executor corresponding to the green_mode.
- Otherwise it returns the global wait callable for the given green_mode.
-
- :returns: wait callable"""
- # Get green mode
- if green_mode is None:
- green_mode = get_object_green_mode(obj)
- # Get waiter
- waiter = get_waiter(green_mode)
- # Asyncio corner case
- if green_mode == GreenMode.Asyncio:
- executors = getattr(obj, "_executors", {})
- executor = executors.get(GreenMode.Asyncio)
- if executor is None:
- return waiter
- return partial(waiter, loop=executor.loop)
- # Return waiter
- return waiter
+def green(fn=None, consume_green_mode=True):
+ """Make a function green. Can be used as a decorator."""
+ def decorator(fn):
+ @wraps(fn)
+ def greener(obj, *args, **kwargs):
+ args = (obj,) + args
+ wait = kwargs.pop('wait', None)
+ timeout = kwargs.pop('timeout', None)
+ access = kwargs.pop if consume_green_mode else kwargs.get
+ green_mode = access('green_mode', None)
+ executor = get_object_executor(obj, green_mode)
+ return executor.run(fn, args, kwargs, wait=wait, timeout=timeout)
-# Green decorators
+ return greener
-def green(fn):
- """make a method green. Can be used as a decorator"""
-
- @wraps(fn)
- def greener(self, *args, **kwargs):
- # first take out all green parameters
- green_mode = kwargs.pop('green_mode', get_object_green_mode(self))
- wait = kwargs.pop('wait', get_wait_default_value(green_mode))
- timeout = kwargs.pop('timeout', None)
-
- # get the proper submitable for the given green_mode
- submitter = get_object_submitter(self, green_mode)
- waiter = get_object_waiter(self, green_mode)
-
- # submit the method
- ret = submitter(fn, self, *args, **kwargs)
-
- # return the proper result
- return waiter(ret, timeout=timeout) if wait else ret
- return greener
+ if fn is None:
+ return decorator
+ return decorator(fn)
-def green_cb(fn, green_mode=None):
- """return a green verion of the given callback."""
- event_loop = get_event_loop(green_mode)
- if event_loop is None:
- return fn
+def green_callback(fn, obj=None, green_mode=None):
+ """Return a green verion of the given callback."""
+ executor = get_object_executor(obj, green_mode)
@wraps(fn)
def greener(*args, **kwargs):
- event_loop.submit(fn, *args, **kwargs)
+ return executor.submit(fn, *args, **kwargs)
return greener
diff --git a/tango/group.py b/tango/group.py
index 687329f..47b57d6 100644
--- a/tango/group.py
+++ b/tango/group.py
@@ -169,15 +169,16 @@ def __init_proxy_Group():
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.__func__.__doc__ = _RealGroup.add.__doc__
- # Group.get_group.__func__.__doc__ = _RealGroup.get_group.__doc__
- # Group.__doc__ = _RealGroup.__doc__
+ # Group.add.__func__.__doc__ = _RealGroup.add.__doc__
+ # Group.get_group.__func__.__doc__ = _RealGroup.get_group.__doc__
+ # Group.__doc__ = _RealGroup.__doc__
def __doc_Group():
@@ -259,13 +260,13 @@ def __doc_Group():
Return : None
Throws :
- """ )
+ """)
document_method("remove_all", """
remove_all(self) -> None
Removes all elements in the _RealGroup. After such a call, the _RealGroup is empty.
- """ )
+ """)
document_method("contains", """
contains(self, pattern, forward=True) -> bool
@@ -284,7 +285,6 @@ def __doc_Group():
Throws :
""")
-
document_method("get_device", """
get_device(self, dev_name) -> DeviceProxy
get_device(self, idx) -> DeviceProxy
@@ -439,7 +439,7 @@ def __doc_Group():
New in PyTango 7.0.0
""")
-# Tango methods (~ DeviceProxy interface)
+ # Tango methods (~ DeviceProxy interface)
document_method("ping", """
ping(self, forward=True) -> bool
@@ -541,7 +541,7 @@ def __doc_Group():
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
@@ -561,7 +561,7 @@ def __doc_Group():
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>
@@ -669,11 +669,11 @@ def __doc_Group():
Throws :
""")
- def document_method(method_name, desc, append=True):
+ def document_group_method(method_name, desc, append=True):
return __document_method(Group, method_name, desc, append)
- document_method("add", _RealGroup._add.__doc__, False)
- document_method("add", """
+ document_group_method("add", _RealGroup._add.__doc__, False)
+ document_group_method("add", """
add(self, subgroup, timeout_ms=-1) -> None
Attaches a (sub)_RealGroup.
@@ -692,7 +692,7 @@ def __doc_Group():
Throws : TypeError, ArgumentError
""")
- document_method("command_inout", """
+ document_group_method("command_inout", """
command_inout(self, cmd_name, forward=True) -> sequence<GroupCmdReply>
command_inout(self, cmd_name, param, forward=True) -> sequence<GroupCmdReply>
command_inout(self, cmd_name, param_list, forward=True) -> sequence<GroupCmdReply>
@@ -712,21 +712,21 @@ def __doc_Group():
Return : (sequence<GroupCmdReply>)
""")
- document_method("read_attribute", """
+ document_group_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", """
+ document_group_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", """
+ document_group_method("write_attribute", """
write_attribute(self, attr_name, value, forward=True, multi=False) -> sequence<GroupReply>
Just a shortcut to do:
diff --git a/tango/group_reply.py b/tango/group_reply.py
index f717bdd..c7baa9d 100644
--- a/tango/group_reply.py
+++ b/tango/group_reply.py
@@ -20,9 +20,11 @@ __docformat__ = "restructuredtext"
from .utils import document_method as __document_method
from ._tango import GroupReply, GroupCmdReply, GroupAttrReply, 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
@@ -34,16 +36,18 @@ def __GroupAttrReply__get_data(self, extract_as=ExtractAs.Numpy):
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)
@@ -71,7 +75,7 @@ def __doc_GroupReply():
Parameters : None
Return : (any) Whatever is stored there, or None.
- """ )
+ """)
__document_method(GroupCmdReply, "get_data_raw", """
get_data_raw(self) -> any
@@ -81,7 +85,7 @@ def __doc_GroupReply():
Parameters : None
Return : (DeviceData) Whatever is stored there, or None.
- """ )
+ """)
__document_method(GroupAttrReply, "get_data", """
get_data(self, extract_as=ExtractAs.Numpy) -> DeviceAttribute
@@ -92,7 +96,8 @@ def __doc_GroupReply():
- extract_as : (ExtractAs)
Return : (DeviceAttribute) Whatever is stored there, or None.
- """ )
+ """)
+
def group_reply_init(doc=True):
__init_GroupReply()
diff --git a/tango/group_reply_list.py b/tango/group_reply_list.py
index 6c6eba3..ed5d6d9 100644
--- a/tango/group_reply_list.py
+++ b/tango/group_reply_list.py
@@ -31,15 +31,15 @@ def __GroupReplyList__getitem(self, item):
# 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 range(*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]
@@ -56,12 +56,14 @@ def __GroupReplyList__getitem(self, 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 range(len(self)):
yield self[x]
+
def __init_GroupReplyList():
GroupReplyList.__GroupReplyList_original_getitem = GroupReplyList.__getitem__
GroupReplyList.__getitem__ = __GroupReplyList__getitem
@@ -76,9 +78,11 @@ def __init_GroupReplyList():
GroupCmdReplyList.__iter__ = __GroupReplyList__iter
GroupAttrReplyList.__iter__ = __GroupReplyList__iter
+
def __doc_GroupReplyList():
pass
+
def group_reply_list_init(doc=True):
__init_GroupReplyList()
if doc:
diff --git a/tango/log4tango.py b/tango/log4tango.py
index 97a16df..c9c4437 100644
--- a/tango/log4tango.py
+++ b/tango/log4tango.py
@@ -18,23 +18,23 @@ To access these members use directly :mod:`tango` module and NOT tango.log4tango
Example::
import tango
-
+
class MyDev(tango.Device_4Impl):
-
+
tango.InfoIt()
def read_Current(self, attr):
attr.set_value(self._current)
"""
-__all__ = [ "TangoStream", "LogIt", "DebugIt", "InfoIt", "WarnIt",
- "ErrorIt", "FatalIt" ]
+__all__ = ["TangoStream", "LogIt", "DebugIt", "InfoIt", "WarnIt",
+ "ErrorIt", "FatalIt"]
__docformat__ = "restructuredtext"
import functools
+
class TangoStream:
-
def __init__(self, fn):
self._fn = fn
self._accum = ""
@@ -47,26 +47,27 @@ class TangoStream:
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]
+ # 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:`tango.DeviceImpl` subclass. The idea is to log the entrance and
+ """A class designed to be a decorator of any method of a
+ :class:`tango.DeviceImpl` subclass. The idea is to log the entrance and
exit of any decorated method.
Example::
-
+
class MyDevice(tango.Device_4Impl):
-
+
@tango.LogIt()
def read_Current(self, attr):
attr.set_value(self._current, 1)
@@ -80,10 +81,10 @@ class LogIt(object):
* 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)
@@ -95,7 +96,7 @@ class LogIt(object):
def __compact_elem(self, v, maxlen=25):
v = repr(v)
if len(v) > maxlen:
- v = v[:maxlen-6] + " [...]"
+ v = v[:maxlen - 6] + " [...]"
return v
def __compact_elems(self, elems):
@@ -110,7 +111,7 @@ class LogIt(object):
return "%s=%s" % (k, self.__compact(v, maxlen=maxlen))
def __compact_dict(self, d, maxlen=None):
- return ( self.__compact_item(k,v) for k,v in d.items() )
+ return (self.__compact_item(k, v) for k, v in d.items())
def __compact_dict_str(self, d, maxlen=None):
return ", ".join(self.__compact_dict(d, maxlen=maxlen))
@@ -148,19 +149,20 @@ class LogIt(object):
if self._show_ret:
sret = self.__compact_elem(ret) + " "
log("{0}<- {1}()".format(sret, f_name))
+
log_stream._wrapped = f
return log_stream
class DebugIt(LogIt):
- """A class designed to be a decorator of any method of a
- :class:`tango.DeviceImpl` subclass. The idea is to log the entrance and
+ """A class designed to be a decorator of any method of a
+ :class:`tango.DeviceImpl` subclass. The idea is to log the entrance and
exit of any decorated method as DEBUG level records.
Example::
-
+
class MyDevice(tango.Device_4Impl):
-
+
@tango.DebugIt()
def read_Current(self, attr):
attr.set_value(self._current, 1)
@@ -181,20 +183,20 @@ class DebugIt(LogIt):
class InfoIt(LogIt):
- """A class designed to be a decorator of any method of a
- :class:`tango.DeviceImpl` subclass. The idea is to log the entrance and
+ """A class designed to be a decorator of any method of a
+ :class:`tango.DeviceImpl` subclass. The idea is to log the entrance and
exit of any decorated method as INFO level records.
Example::
-
+
class MyDevice(tango.Device_4Impl):
-
+
@tango.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)
@@ -209,14 +211,14 @@ class InfoIt(LogIt):
class WarnIt(LogIt):
- """A class designed to be a decorator of any method of a
- :class:`tango.DeviceImpl` subclass. The idea is to log the entrance and
+ """A class designed to be a decorator of any method of a
+ :class:`tango.DeviceImpl` subclass. The idea is to log the entrance and
exit of any decorated method as WARN level records.
Example::
-
+
class MyDevice(tango.Device_4Impl):
-
+
@tango.WarnIt()
def read_Current(self, attr):
attr.set_value(self._current, 1)
@@ -228,7 +230,7 @@ class WarnIt(LogIt):
* 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()
@@ -237,14 +239,14 @@ class WarnIt(LogIt):
class ErrorIt(LogIt):
- """A class designed to be a decorator of any method of a
- :class:`tango.DeviceImpl` subclass. The idea is to log the entrance and
+ """A class designed to be a decorator of any method of a
+ :class:`tango.DeviceImpl` subclass. The idea is to log the entrance and
exit of any decorated method as ERROR level records.
Example::
-
+
class MyDevice(tango.Device_4Impl):
-
+
@tango.ErrorIt()
def read_Current(self, attr):
attr.set_value(self._current, 1)
@@ -256,7 +258,7 @@ class ErrorIt(LogIt):
* 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()
@@ -265,14 +267,14 @@ class ErrorIt(LogIt):
class FatalIt(LogIt):
- """A class designed to be a decorator of any method of a
- :class:`tango.DeviceImpl` subclass. The idea is to log the entrance and
+ """A class designed to be a decorator of any method of a
+ :class:`tango.DeviceImpl` subclass. The idea is to log the entrance and
exit of any decorated method as FATAL level records.
Example::
-
+
class MyDevice(tango.Device_4Impl):
-
+
@tango.FatalIt()
def read_Current(self, attr):
attr.set_value(self._current, 1)
@@ -284,7 +286,7 @@ class FatalIt(LogIt):
* 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()
diff --git a/tango/pipe.py b/tango/pipe.py
index 407e031..f93f8c8 100644
--- a/tango/pipe.py
+++ b/tango/pipe.py
@@ -11,10 +11,8 @@
__all__ = ['PipeConfig']
-
-
from ._tango import Pipe, PipeWriteType, UserDefaultPipeProp, \
- AttrDataFormat, CmdArgType, DevState, DispLevel, constants
+ CmdArgType, DevState, DispLevel, constants
from .utils import scalar_to_array_type, TO_TANGO_TYPE, \
is_non_str_seq, is_pure_str, is_integer, is_number
@@ -38,8 +36,8 @@ class PipeConfig(object):
def __get_pipe_type_simple(obj):
if is_non_str_seq(obj):
if len(obj) == 2 and \
- is_pure_str(obj[0]) and \
- (is_non_str_seq(obj[1]) or isinstance(obj[1], dict)):
+ is_pure_str(obj[0]) and \
+ (is_non_str_seq(obj[1]) or isinstance(obj[1], dict)):
tg_type = CmdArgType.DevPipeBlob
else:
tg_type = __get_pipe_type(obj[0])
@@ -58,9 +56,8 @@ def __get_pipe_type_simple(obj):
raise ValueError('Cannot determine object tango type')
return tg_type
-
+
def __get_pipe_type_numpy_support(obj):
- import numpy
try:
ndim, dtype = obj.ndim, str(obj.dtype)
except AttributeError:
@@ -124,6 +121,10 @@ def __Pipe__set_value(self, value):
self._set_value(value)
+def __Pipe__get_value(self):
+ return (self.get_root_blob_name(), self._get_value())
+
+
def __init_Pipe():
Pipe.set_value = __Pipe__set_value
@@ -134,9 +135,9 @@ def __doc_UserDefaultPipeProp():
UserDefaultPipeProp.__doc__ = """
User class to set pipe default properties.
- This class is used to set pipe default properties.
- Three levels of pipe properties setting are implemented within Tango.
- The highest property setting level is the database.
+ This class is used to set pipe default properties.
+ Three levels of pipe properties setting are implemented within Tango.
+ The highest property setting level is the database.
Then the user default (set using this UserDefaultPipeProp class) and finally
a Tango library default value
"""
@@ -144,25 +145,25 @@ def __doc_UserDefaultPipeProp():
document_method("set_label", """
set_label(self, def_label) -> None
- Set default label property.
+ Set default label property.
Parameters :
- - def_label : (str) the user default label property
+ - def_label : (str) the user default label property
Return : None
- """ )
-
+ """)
+
document_method("set_description", """
set_description(self, def_description) -> None
- Set default description property.
+ Set default description property.
- Parameters :
- - def_description : (str) the user default description property
+ Parameters :
+ - def_description : (str) the user default description property
Return : None
- """ )
+ """)
def pipe_init(doc=True):
__init_Pipe()
if doc:
- __doc_UserDefaultPipeProp()
+ __doc_UserDefaultPipeProp()
diff --git a/tango/pipe_data.py b/tango/pipe_data.py
index 2b94518..c54eda5 100644
--- a/tango/pipe_data.py
+++ b/tango/pipe_data.py
@@ -16,21 +16,20 @@ This is an internal PyTango module.
from __future__ import with_statement
from __future__ import print_function
-__all__ = [ "PipeData" ]
+__all__ = ["PipeData"]
__docformat__ = "restructuredtext"
import inspect
-from ._tango import Except, CmdArgType, DispLevel, AttrDataFormat, \
- Pipe, PipeWriteType, PipeSerialModel, UserDefaultPipeProp
+from ._tango import Except, DispLevel, Pipe, PipeWriteType, UserDefaultPipeProp
from .utils import is_non_str_seq, is_pure_str
class PipeData(object):
"""A helper class that contains the same information one of the items in
DeviceClass.pipe_list but in object form"""
-
+
def __init__(self, name, class_name, pipe_info=None):
self.class_name = class_name
self.pipe_name = name
@@ -58,10 +57,10 @@ class PipeData(object):
self = cls(name, class_name)
self.build_from_dict(pipe_dict)
return self
-
+
def build_from_dict(self, pipe_dict):
self.display_level = pipe_dict.pop('display_level', DispLevel.OPERATOR)
-
+
is_access_explicit = "access" in pipe_dict
if is_access_explicit:
self.pipe_write = pipe_dict.pop('access')
@@ -73,7 +72,7 @@ class PipeData(object):
self.pipe_write = PipeWriteType.PIPE_READ_WRITE
else:
self.pipe_write = PipeWriteType.PIPE_READ
-
+
fread = pipe_dict.pop('fget', pipe_dict.pop('fread', None))
if fread is not None:
if is_pure_str(fread):
@@ -91,13 +90,13 @@ class PipeData(object):
if is_pure_str(fisallowed):
self.is_allowed_name = fisallowed
elif inspect.isroutine(fisallowed):
- self.is_allowed_name = fisallowed.__name__
+ self.is_allowed_name = fisallowed.__name__
self.pipe_class = pipe_dict.pop("klass", Pipe)
self.pipe_args.extend((self.pipe_name, self.display_level, self.pipe_write))
if len(pipe_dict):
self.pipe_prop = self.__create_user_default_pipe_prop(pipe_dict)
return self
-
+
def _set_name(self, name):
old_name = self.pipe_name
self.pipe_name = name
@@ -109,7 +108,7 @@ class PipeData(object):
self.write_method_name = "write_" + name
if self.is_allowed_name is None:
self.is_allowed_name = "is_" + name + "_allowed"
-
+
def __throw_exception(self, msg, meth="create_pipe()"):
Except.throw_exception("PyDs_WrongPipeDefinition", msg, meth)
@@ -120,10 +119,10 @@ class PipeData(object):
doc = extra_info.pop('doc', None)
if doc is not None:
extra_info['description'] = doc
-
+
for k, v in extra_info.items():
k_lower = k.lower()
- method_name = "set_%s" % k_lower.replace(' ','_')
+ method_name = "set_%s" % k_lower.replace(' ', '_')
if hasattr(p, method_name):
method = getattr(p, method_name)
method(str(v))
@@ -140,28 +139,28 @@ class PipeData(object):
pipe_name = self.pipe_name
throw_ex = self.__throw_exception
# check for well defined pipe info
-
+
# check parameter
if not is_non_str_seq(pipe_info):
throw_ex("Wrong data type for value for describing pipe %s in "
- "class %s\nMust be a sequence with 1 or 2 elements"
+ "class %s\nMust be a sequence with 1 or 2 elements"
% (pipe_name, name))
if len(pipe_info) < 1 or len(pipe_info) > 2:
throw_ex("Wrong number of argument for describing pipe %s in "
"class %s\nMust be a sequence with 1 or 2 elements"
% (pipe_name, name))
-
+
extra_info = {}
if len(pipe_info) == 2:
# pipe_info[1] must be a dictionary
# extra_info = pipe_info[1], with all the keys lowercase
for k, v in pipe_info[1].items():
extra_info[k.lower()] = v
-
+
pipe_info = pipe_info[0]
- #get write type
+ # get write type
try:
self.pipe_write = PipeWriteType(pipe_info)
except:
@@ -169,7 +168,7 @@ class PipeData(object):
"pipe %s in class %s\nPipe write type must be a "
"tango.PipeWriteType" % (pipe_name, name))
try:
- self.display_level = DispLevel(extra_info.get("display level",
+ self.display_level = DispLevel(extra_info.get("display level",
DispLevel.OPERATOR))
except:
throw_ex("Wrong display level in pipe information for "
@@ -179,12 +178,12 @@ class PipeData(object):
self.pipe_class = extra_info.get("klass", Pipe)
self.pipe_args.extend((self.pipe_name, self.display_level, self.pipe_write))
-
+
pipe_prop = None
if extra_info:
pipe_prop = self.__create_user_default_pipe_prop(extra_info)
self.pipe_prop = pipe_prop
-
+
def to_pipe(self):
pipe = self.pipe_class(*self.pipe_args)
if self.pipe_prop is not None:
diff --git a/tango/pytango_init.py b/tango/pytango_init.py
index dd109a5..64ce253 100644
--- a/tango/pytango_init.py
+++ b/tango/pytango_init.py
@@ -48,7 +48,7 @@ __DOC = True
def init_constants():
import sys
import platform
-
+
tg_ver = tuple(map(int, constants.TgLibVers.split(".")))
tg_ver_str = "0x%02d%02d%02d00" % (tg_ver[0], tg_ver[1], tg_ver[2])
constants.TANGO_VERSION_HEX = int(tg_ver_str, 16)
@@ -63,7 +63,7 @@ def init_constants():
TANGO_VERSION = constants.TANGO_VERSION
BOOST_VERSION = constants.BOOST_VERSION
NUMPY_VERSION = constants.NUMPY_VERSION
- #UNAME = tuple(map(str, json.loads(constants.UNAME)))
+ # UNAME = tuple(map(str, json.loads(constants.UNAME)))
tg_rt_ver_nb = _get_tango_lib_release()
tg_rt_major_ver = tg_rt_ver_nb // 100
diff --git a/tango/pytango_pprint.py b/tango/pytango_pprint.py
index 3b84862..674008f 100644
--- a/tango/pytango_pprint.py
+++ b/tango/pytango_pprint.py
@@ -17,22 +17,20 @@ __all__ = ["pytango_pprint_init"]
__docformat__ = "restructuredtext"
-import operator
-
from ._tango import (StdStringVector, StdLongVector, CommandInfoList,
- AttributeInfoList, AttributeInfoListEx, PipeInfoList,
- DeviceDataHistoryList,
- GroupReplyList, GroupAttrReplyList, GroupCmdReplyList,
- DbData, DbDevInfos, DbDevExportInfos, DbDevImportInfos, DbHistoryList,
- LockerInfo, DevCommandInfo, AttributeDimension, CommandInfo, PipeInfo,
- DeviceInfo, DeviceAttributeConfig, AttributeInfo, AttributeAlarmInfo,
- ChangeEventInfo, PeriodicEventInfo, ArchiveEventInfo,
- AttributeEventInfo, AttributeInfoEx,
- DeviceAttribute, DeviceAttributeHistory, DeviceData, DeviceDataHistory,
- DevicePipe, DbDatum, DbDevInfo, DbDevImportInfo, DbDevExportInfo,
- DbServerInfo, GroupReply, GroupAttrReply, GroupCmdReply,
- DevError, EventData, AttrConfEventData, DataReadyEventData,
- TimeVal, DevFailed, CmdArgType)
+ AttributeInfoList, AttributeInfoListEx, PipeInfoList,
+ DeviceDataHistoryList,
+ GroupReplyList, GroupAttrReplyList, GroupCmdReplyList,
+ DbData, DbDevInfos, DbDevExportInfos, DbDevImportInfos, DbHistoryList,
+ LockerInfo, DevCommandInfo, AttributeDimension, CommandInfo, PipeInfo,
+ DeviceInfo, DeviceAttributeConfig, AttributeInfo, AttributeAlarmInfo,
+ ChangeEventInfo, PeriodicEventInfo, ArchiveEventInfo,
+ AttributeEventInfo, AttributeInfoEx,
+ DeviceAttribute, DeviceAttributeHistory, DeviceData, DeviceDataHistory,
+ DevicePipe, DbDatum, DbDevInfo, DbDevImportInfo, DbDevExportInfo,
+ DbServerInfo, GroupReply, GroupAttrReply, GroupCmdReply,
+ DevError, EventData, AttrConfEventData, DataReadyEventData,
+ TimeVal, DevFailed, CmdArgType)
from .device_server import AttributeAlarm, EventProperties
from .device_server import ChangeEventProp, PeriodicEventProp, ArchiveEventProp
@@ -40,51 +38,61 @@ from .device_server import AttributeConfig, AttributeConfig_2
from .device_server import AttributeConfig_3, AttributeConfig_5
import collections
+
def __inc_param(obj, name):
- ret = not name.startswith('_')
- ret &= not name in ('except_flags',)
- ret &= not isinstance(getattr(obj,name), collections.Callable)
+ ret = not name.startswith('_')
+ ret &= name not in ('except_flags',)
+ ret &= not isinstance(getattr(obj, name), collections.Callable)
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)])
+ 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"
+ 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 "[]"
+ _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, PipeInfoList,
@@ -96,16 +104,19 @@ def __registerSeqStr():
seq.__str__ = _SeqStr
seq.__repr__ = _SeqRepr
+
def __str__DevFailed(self):
if isinstance(self.args, collections.Sequence):
- return 'DevFailed[\n%s]' % '\n'.join(map(str,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 ")
+ desc = self.desc.replace("\n", "\n ")
s = """DevError[
desc = %s
origin = %s
@@ -113,20 +124,21 @@ def __str__DevError(self):
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, PipeInfo,
- DeviceAttribute, DeviceAttributeHistory, DeviceData, DeviceDataHistory,
- DevicePipe, DbDatum, DbDevInfo, DbDevImportInfo, DbDevExportInfo,
- DbServerInfo, GroupReply, GroupAttrReply, GroupCmdReply,
- DevError, EventData, AttrConfEventData, DataReadyEventData,
- AttributeConfig, AttributeConfig_2, AttributeConfig_3,
- AttributeConfig_5,
- ChangeEventProp, PeriodicEventProp, ArchiveEventProp,
- AttributeAlarm, EventProperties)
+ DeviceInfo, DeviceAttributeConfig, AttributeInfo, AttributeAlarmInfo,
+ ChangeEventInfo, PeriodicEventInfo, ArchiveEventInfo,
+ AttributeEventInfo, AttributeInfoEx, PipeInfo,
+ DeviceAttribute, DeviceAttributeHistory, DeviceData, DeviceDataHistory,
+ DevicePipe, DbDatum, DbDevInfo, DbDevImportInfo, DbDevExportInfo,
+ DbServerInfo, GroupReply, GroupAttrReply, GroupCmdReply,
+ DevError, EventData, AttrConfEventData, DataReadyEventData,
+ AttributeConfig, AttributeConfig_2, AttributeConfig_3,
+ AttributeConfig_5,
+ ChangeEventProp, PeriodicEventProp, ArchiveEventProp,
+ AttributeAlarm, EventProperties)
for struct in structs:
struct.__str__ = __str__Struct
@@ -143,6 +155,7 @@ def __registerStructStr():
DevError.__str__ = __str__DevError
+
def pytango_pprint_init(doc=True):
__registerSeqStr()
__registerStructStr()
diff --git a/tango/pyutil.py b/tango/pyutil.py
index ebe7225..2fb2431 100644
--- a/tango/pyutil.py
+++ b/tango/pyutil.py
@@ -13,7 +13,7 @@
This is an internal PyTango module.
"""
-__all__ = [ "Util", "pyutil_init" ]
+__all__ = ["Util", "pyutil_init"]
__docformat__ = "restructuredtext"
@@ -22,7 +22,7 @@ import copy
from ._tango import Util, Except, DevFailed, DbDevInfo
from .utils import document_method as __document_method
-#from utils import document_static_method as __document_static_method
+# from utils import document_static_method as __document_static_method
from .globals import class_list, cpp_class_list, get_constructed_classes
import collections
@@ -31,9 +31,10 @@ 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:]
+ dev_name = dev_name[dev_name.index("/") + 1:]
return dev_name.lower()
+
#
# Methods on Util
#
@@ -49,6 +50,7 @@ def __Util__get_class_list(self):
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
@@ -81,8 +83,8 @@ def __Util__create_device(self, klass_name, device_name, alias=None, cb=None):
Return : None"""
if cb is not None and not isinstance(cb, collections.Callable):
Except.throw_exception("PyAPI_InvalidParameter",
- "The optional cb parameter must be a python callable",
- "Util.create_device")
+ "The optional cb parameter must be a python callable",
+ "Util.create_device")
db = self.get_database()
@@ -97,8 +99,8 @@ def __Util__create_device(self, klass_name, device_name, alias=None, cb=None):
# 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")
+ "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()
@@ -110,8 +112,8 @@ def __Util__create_device(self, klass_name, device_name, alias=None, cb=None):
break
if klass is None:
Except.throw_exception("PyAPI_UnknownDeviceClass",
- "The device class %s could not be found" % klass_name,
- "Util.create_device")
+ "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()
@@ -141,6 +143,7 @@ def __Util__create_device(self, klass_name, device_name, alias=None, cb=None):
pass
db.delete_device(device_name)
+
def __Util__delete_device(self, klass_name, device_name):
"""
delete_device(self, klass_name, device_name) -> None
@@ -171,8 +174,8 @@ def __Util__delete_device(self, klass_name, device_name):
# 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")
+ "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)
@@ -183,12 +186,12 @@ def __Util__delete_device(self, klass_name, device_name):
p = dev_name.index("::")
dev_name = dev_name[:p] + dev_name[p:].lower()
if dev_name == class_device_name:
- device_exists =True
+ 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")
+ "The device %s is not defined in this server" % class_device_name,
+ "Util.delete_device")
db.delete_device(device_name)
@@ -197,11 +200,13 @@ def __Util__delete_device(self, klass_name, device_name):
dc = dimpl.get_device_class()
dc.device_destroyer(device_name)
+
def __Util__init__(self, args):
args = copy.copy(args)
args[0] = os.path.splitext(args[0])[0]
Util.__init_orig__(self, args)
+
def __Util__add_TgClass(self, klass_device_class, klass_device,
device_class_name=None):
"""Register a new python tango class. Example::
@@ -231,6 +236,7 @@ def __Util__add_Cpp_TgClass(self, device_class_name, tango_device_class_name):
Use :meth:`tango.Util.add_class` instead."""
cpp_class_list.append((device_class_name, tango_device_class_name))
+
def __Util__add_class(self, *args, **kwargs):
"""
add_class(self, class<DeviceClass>, class<DeviceImpl>, language="python") -> None
@@ -251,6 +257,7 @@ def __Util__add_class(self, *args, **kwargs):
f = f = self.add_Cpp_TgClass
return f(*args)
+
def __init_Util():
Util.__init_orig__ = Util.__init__
Util.__init__ = __Util__init__
@@ -261,8 +268,8 @@ def __init_Util():
Util.create_device = __Util__create_device
Util.delete_device = __Util__delete_device
-def __doc_Util():
+def __doc_Util():
Util.__doc__ = """\
This class is a used to store TANGO device server process data and to
provide the user with a set of utilities method.
@@ -278,21 +285,21 @@ 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 prints a message and aborts the device server process
-#
-# Parameters :
-# - exit : (bool)
-#
-# Return : (Util) the tango Util object
-# """ )
+ # 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 prints a message and aborts the device server process
+ #
+ # Parameters :
+ # - exit : (bool)
+ #
+ # Return : (Util) the tango Util object
+ # """ )
document_method("set_trace_level", """
set_trace_level(self, level) -> None
@@ -302,7 +309,7 @@ def __doc_Util():
Parameters :
- level : (int) the new process level
Return : None
- """ )
+ """)
document_method("get_trace_level", """
get_trace_level(self) -> int
@@ -311,7 +318,7 @@ def __doc_Util():
Parameters : None
Return : (int) the process trace level.
- """ )
+ """)
document_method("get_ds_inst_name", """
get_ds_inst_name(self) -> str
@@ -322,7 +329,7 @@ def __doc_Util():
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
@@ -333,7 +340,7 @@ def __doc_Util():
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
@@ -345,7 +352,7 @@ def __doc_Util():
Return : (str) device server name
New in PyTango 3.0.4
- """ )
+ """)
document_method("get_host_name", """
get_host_name(self) -> str
@@ -356,7 +363,7 @@ def __doc_Util():
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
@@ -367,7 +374,7 @@ def __doc_Util():
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
@@ -376,7 +383,7 @@ def __doc_Util():
Parameters : None
Return : (int) the device server process identifier
- """ )
+ """)
document_method("get_tango_lib_release", """
get_tango_lib_release(self) -> int
@@ -386,7 +393,7 @@ def __doc_Util():
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
@@ -397,7 +404,7 @@ def __doc_Util():
Return : (str) the IDL TANGO version.
New in PyTango 3.0.4
- """ )
+ """)
document_method("get_server_version", """
get_server_version(self) -> str
@@ -406,7 +413,7 @@ def __doc_Util():
Parameters : None
Return : (str) the device server version.
- """ )
+ """)
document_method("set_server_version", """
set_server_version(self, vers) -> None
@@ -416,7 +423,7 @@ def __doc_Util():
Parameters :
- vers : (str) the device server version
Return : None
- """ )
+ """)
document_method("set_serial_model", """
set_serial_model(self, ser) -> None
@@ -427,7 +434,7 @@ def __doc_Util():
- 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
@@ -436,7 +443,7 @@ def __doc_Util():
Parameters : None
Return : (SerialModel) the serialization model
- """ )
+ """)
document_method("connect_db", """
connect_db(self) -> None
@@ -447,7 +454,7 @@ def __doc_Util():
Parameters : None
Return : None
- """ )
+ """)
document_method("reset_filedatabase", """
reset_filedatabase(self) -> None
@@ -456,7 +463,7 @@ def __doc_Util():
Parameters : None
Return : None
- """ )
+ """)
document_method("unregister_server", """
unregister_server(self) -> None
@@ -465,7 +472,7 @@ def __doc_Util():
Parameters : None
Return : None
- """ )
+ """)
document_method("get_dserver_device", """
get_dserver_device(self) -> DServer
@@ -476,7 +483,7 @@ def __doc_Util():
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
@@ -488,7 +495,7 @@ def __doc_Util():
Return : None
Throws : DevFailed If the device pattern initialistaion failed
- """ )
+ """)
document_method("server_run", """
server_run(self) -> None
@@ -500,7 +507,7 @@ def __doc_Util():
Parameters : None
Return : None
- """ )
+ """)
document_method("trigger_cmd_polling", """
trigger_cmd_polling(self, dev, name) -> None
@@ -515,7 +522,7 @@ def __doc_Util():
Return : None
Throws : DevFailed If the call failed
- """ )
+ """)
document_method("trigger_attr_polling", """
trigger_attr_polling(self, dev, name) -> None
@@ -528,7 +535,7 @@ def __doc_Util():
- 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
@@ -540,7 +547,7 @@ def __doc_Util():
Return : None
New in PyTango 7.0.0
- """ )
+ """)
document_method("get_polling_threads_pool_size", """
get_polling_threads_pool_size(self) -> int
@@ -549,7 +556,7 @@ def __doc_Util():
Parameters : None
Return : (int) the maximun number of threads in the polling threads pool
- """ )
+ """)
document_method("is_svr_starting", """
is_svr_starting(self) -> bool
@@ -560,7 +567,7 @@ def __doc_Util():
Return : (bool) True if the server is in its starting phase
New in PyTango 8.0.0
- """ )
+ """)
document_method("is_svr_shutting_down", """
is_svr_shutting_down(self) -> bool
@@ -571,7 +578,7 @@ def __doc_Util():
Return : (bool) True if the server is in its shutting down phase.
New in PyTango 8.0.0
- """ )
+ """)
document_method("is_device_restarting", """
is_device_restarting(self, (str)dev_name) -> bool
@@ -584,7 +591,7 @@ def __doc_Util():
Return : (bool) True if the device is restarting.
New in PyTango 8.0.0
- """ )
+ """)
document_method("get_sub_dev_diag", """
get_sub_dev_diag(self) -> SubDevDiag
@@ -595,7 +602,7 @@ def __doc_Util():
Return : (SubDevDiag) the sub device manager
New in PyTango 7.0.0
- """ )
+ """)
document_method("reset_filedatabase", """
reset_filedatabase(self) -> None
@@ -606,7 +613,7 @@ def __doc_Util():
Return : None
New in PyTango 7.0.0
- """ )
+ """)
document_method("get_database", """
get_database(self) -> Database
@@ -617,7 +624,7 @@ def __doc_Util():
Return : (Database) the database
New in PyTango 7.0.0
- """ )
+ """)
document_method("unregister_server", """
unregister_server(self) -> None
@@ -630,7 +637,7 @@ def __doc_Util():
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>
@@ -645,7 +652,7 @@ def __doc_Util():
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
@@ -657,7 +664,7 @@ def __doc_Util():
Return : (DeviceImpl) The device reference
New in PyTango 7.0.0
- """ )
+ """)
document_method("get_dserver_device", """
get_dserver_device(self) -> DServer
@@ -668,7 +675,7 @@ def __doc_Util():
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>
@@ -681,7 +688,7 @@ def __doc_Util():
Return : (sequence<DeviceImpl>) the list of device objects
New in PyTango 7.0.0
- """ )
+ """)
document_method("server_set_event_loop", """
server_set_event_loop(self, event_loop) -> None
@@ -715,7 +722,7 @@ def __doc_Util():
Return : None
New in PyTango 8.1.0
- """ )
+ """)
# document_static_method("init_python", """
diff --git a/tango/release.py b/tango/release.py
index 2b9eb40..48cba49 100644
--- a/tango/release.py
+++ b/tango/release.py
@@ -45,7 +45,7 @@ class Release:
- license: (str) the license
"""
name = 'PyTango'
- version_info = (9, 2, 1)
+ version_info = (9, 2, 2)
version = '.'.join(map(str, version_info[:3]))
release = ''.join(map(str, version_info[3:]))
separator = '.' if 'dev' in release or 'post' in release else ''
diff --git a/tango/server.py b/tango/server.py
index c683cf4..b0b6ae6 100644
--- a/tango/server.py
+++ b/tango/server.py
@@ -16,7 +16,6 @@ from __future__ import print_function
from __future__ import absolute_import
import sys
-import six
import copy
import inspect
import logging
@@ -24,7 +23,7 @@ import functools
import traceback
from ._tango import AttrDataFormat, AttrWriteType, CmdArgType, PipeWriteType
-from ._tango import DevFailed, Except, GreenMode
+from ._tango import DevFailed, GreenMode, SerialModel
from .attr_data import AttrData
from .pipe_data import PipeData
@@ -32,14 +31,30 @@ from .device_class import DeviceClass
from .device_server import LatestDeviceImpl
from .utils import is_seq, is_non_str_seq
from .utils import scalar_to_array_type, TO_TANGO_TYPE
+from .green import get_green_mode, get_executor
+from .pyutil import Util
__all__ = ["DeviceMeta", "Device", "LatestDeviceImpl", "attribute",
"command", "pipe", "device_property", "class_property",
- "run", "server_run", "get_worker", "get_async_worker",
- "Server"]
+ "run", "server_run", "Server"]
API_VERSION = 2
+# Worker access
+
+_WORKER = get_executor()
+
+
+def set_worker(worker):
+ global _WORKER
+ _WORKER = worker
+
+
+def get_worker():
+ return _WORKER
+
+
+# Helpers
def _get_tango_type_format(dtype=None, dformat=None):
if dformat is None:
@@ -283,17 +298,13 @@ def _get_wrapped_pipe_write_method(pipe, write_method):
if green_mode == GreenMode.Synchronous:
@functools.wraps(write_method)
def write_pipe(self, pipe):
- # TODO
- raise NotImplementedError
- # value = pipe.get_write_value()
- # return write_method(self, value)
+ value = pipe.get_value()
+ return write_method(self, value)
else:
@functools.wraps(write_method)
def write_pipe(self, pipe):
- # TODO
- raise NotImplementedError
- # value = pipe.get_write_value()
- # return get_worker().execute(write_method, self, value)
+ value = pipe.get_value()
+ return get_worker().execute(write_method, self, value)
return write_pipe
@@ -347,6 +358,7 @@ def __patch_standard_device_methods(klass):
@functools.wraps(init_device_orig)
def init_device(self):
return get_worker().execute(init_device_orig, self)
+
setattr(klass, "init_device", init_device)
delete_device_orig = klass.delete_device
@@ -354,6 +366,7 @@ def __patch_standard_device_methods(klass):
@functools.wraps(delete_device_orig)
def delete_device(self):
return get_worker().execute(delete_device_orig, self)
+
setattr(klass, "delete_device", delete_device)
dev_state_orig = klass.dev_state
@@ -361,6 +374,7 @@ def __patch_standard_device_methods(klass):
@functools.wraps(dev_state_orig)
def dev_state(self):
return get_worker().execute(dev_state_orig, self)
+
setattr(klass, "dev_state", dev_state)
dev_status_orig = klass.dev_status
@@ -368,6 +382,7 @@ def __patch_standard_device_methods(klass):
@functools.wraps(dev_status_orig)
def dev_status(self):
return get_worker().execute(dev_status_orig, self)
+
setattr(klass, "dev_status", dev_status)
read_attr_hardware_orig = klass.read_attr_hardware
@@ -375,6 +390,7 @@ def __patch_standard_device_methods(klass):
@functools.wraps(read_attr_hardware_orig)
def read_attr_hardware(self, attr_list):
return get_worker().execute(read_attr_hardware_orig, self, attr_list)
+
setattr(klass, "read_attr_hardware", read_attr_hardware)
always_executed_hook_orig = klass.always_executed_hook
@@ -382,11 +398,11 @@ def __patch_standard_device_methods(klass):
@functools.wraps(always_executed_hook_orig)
def always_executed_hook(self):
return get_worker().execute(always_executed_hook_orig, self)
+
setattr(klass, "always_executed_hook", always_executed_hook)
class _DeviceClass(DeviceClass):
-
def __init__(self, name):
DeviceClass.__init__(self, name)
self.set_type(name)
@@ -434,7 +450,8 @@ def __create_tango_deviceclass_klass(tango_device_klass, attrs=None):
else:
attr_name = attr_obj.attr_name
attr_list[attr_name] = attr_obj
- __patch_attr_methods(tango_device_klass, attr_obj)
+ if not attr_obj.forward:
+ __patch_attr_methods(tango_device_klass, attr_obj)
elif isinstance(attr_obj, pipe):
if attr_obj.pipe_name is None:
attr_obj._set_name(attr_name)
@@ -444,9 +461,12 @@ def __create_tango_deviceclass_klass(tango_device_klass, attrs=None):
__patch_pipe_methods(tango_device_klass, attr_obj)
elif isinstance(attr_obj, device_property):
attr_obj.name = attr_name
+ # if you modify the attr_obj order then you should
+ # take care of the code in get_device_properties()
device_property_list[attr_name] = [attr_obj.dtype,
attr_obj.doc,
- attr_obj.default_value]
+ attr_obj.default_value,
+ attr_obj.mandatory]
elif isinstance(attr_obj, class_property):
attr_obj.name = attr_name
class_property_list[attr_name] = [attr_obj.dtype,
@@ -465,11 +485,11 @@ def __create_tango_deviceclass_klass(tango_device_klass, attrs=None):
device_property_list=device_property_list,
cmd_list=cmd_list, attr_list=attr_list,
pipe_list=pipe_list)
- return type(devclass_name, (_DeviceClass,), devclass_attrs)
+ return type(_DeviceClass)(devclass_name, (_DeviceClass,), devclass_attrs)
def _init_tango_device_klass(tango_device_klass, attrs=None,
- tango_class_name=None):
+ tango_class_name=None):
klass_name = tango_device_klass.__name__
tango_deviceclass_klass = __create_tango_deviceclass_klass(
tango_device_klass, attrs=attrs)
@@ -558,6 +578,7 @@ class BaseDevice(LatestDeviceImpl):
def delete_device(self):
pass
+
delete_device.__doc__ = LatestDeviceImpl.delete_device.__doc__
def read_attr_hardware(self, attr_list):
@@ -591,8 +612,13 @@ class BaseDevice(LatestDeviceImpl):
value = self.prop_util.get_property_values(
prop_name, self.device_property_list)
self._tango_properties[prop_name] = value
+ properties = self.device_property_list[prop_name]
+ mandatory = properties[3]
+ if mandatory and value is None:
+ msg = "Device property {0} is mandatory ".format(prop_name)
+ raise Exception(msg)
except DevFailed as df:
- print(80*"-")
+ print(80 * "-")
print(df)
raise df
@@ -674,7 +700,7 @@ class attribute(AttrData):
access :obj:`~tango.AttrWriteType` :obj:`~tango.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
+ fisallowed :obj:`str` or :obj:`callable` 'is_<attr_name>_allowed' is allowed method name or method object
label :obj:`str` '<attr_name>' attribute label
enum_labels sequence None the list of enumeration labels (enum data type)
doc (or description) :obj:`str` '' attribute description
@@ -699,6 +725,7 @@ class attribute(AttrData):
green_mode :obj:`~tango.GreenMode` None green mode for read and write. None means use server green mode.
read_green_mode :obj:`~tango.GreenMode` None green mode for read. None means use server green mode.
write_green_mode :obj:`~tango.GreenMode` None green mode for write. None means use server green mode.
+ forwarded :obj:`bool` False the attribute should be forwarded if True
===================== ================================ ======================================= =======================================================================================
.. note::
@@ -750,21 +777,27 @@ class attribute(AttrData):
def __init__(self, fget=None, **kwargs):
self._kwargs = dict(kwargs)
- name = kwargs.pop("name", None)
+ self.name = kwargs.pop("name", None)
class_name = kwargs.pop("class_name", None)
- green_mode = kwargs.pop("green_mode", True)
- self.read_green_mode = kwargs.pop("read_green_mode", green_mode)
- self.write_green_mode = kwargs.pop("write_green_mode", green_mode)
-
- if fget:
- if inspect.isroutine(fget):
- self.fget = fget
- if 'doc' not in kwargs and 'description' not in kwargs:
- if fget.__doc__ is not None:
- kwargs['doc'] = fget.__doc__
- kwargs['fget'] = fget
-
- super(attribute, self).__init__(name, class_name)
+ forward = kwargs.get("forwarded", False)
+ if forward:
+ expected = 2 if "label" in kwargs else 1
+ if len(kwargs) > expected:
+ raise TypeError(
+ "Forwarded attributes only support label argument")
+ else:
+ green_mode = kwargs.pop("green_mode", True)
+ self.read_green_mode = kwargs.pop("read_green_mode", green_mode)
+ self.write_green_mode = kwargs.pop("write_green_mode", green_mode)
+
+ if fget:
+ if inspect.isroutine(fget):
+ self.fget = fget
+ if 'doc' not in kwargs and 'description' not in kwargs:
+ if fget.__doc__ is not None:
+ kwargs['doc'] = fget.__doc__
+ kwargs['fget'] = fget
+ super(attribute, self).__init__(self.name, class_name)
self.__doc__ = kwargs.get('doc', kwargs.get('description',
'TANGO attribute'))
if 'dtype' in kwargs:
@@ -859,7 +892,7 @@ class pipe(PipeData):
access :obj:`~tango.PipeWriteType` :obj:`~tango.PipeWriteType.READ` read only/ read write access
fget (or fread) :obj:`str` or :obj:`callable` 'read_<pipe_name>' read method name or method object
fset (or fwrite) :obj:`str` or :obj:`callable` 'write_<pipe_name>' write method name or method object
- is_allowed :obj:`str` or :obj:`callable` 'is_<pipe_name>_allowed' is allowed method name or method object
+ fisallowed :obj:`str` or :obj:`callable` 'is_<pipe_name>_allowed' is allowed method name or method object
label :obj:`str` '<pipe_name>' pipe label
doc (or description) :obj:`str` '' pipe description
green_mode :obj:`~tango.GreenMode` None green mode for read and write. None means use server green mode.
@@ -928,9 +961,6 @@ class pipe(PipeData):
self.__doc__ = kwargs.get('doc', kwargs.get('description',
'TANGO pipe'))
self.build_from_dict(kwargs)
- if self.pipe_write == PipeWriteType.PIPE_READ_WRITE:
- raise NotImplementedError(
- 'writtable pipes not implemented in 9.2.0a')
def get_pipe(self, obj):
dclass = obj.get_device_class()
@@ -954,7 +984,6 @@ class pipe(PipeData):
To be used as a decorator. Will define the decorated method
as a write pipe method to be called when client writes to the pipe
"""
- raise NotImplementedError('writtable pipes not implemented in 9.2.0a')
self.fset = fset
self.pipe_write = PipeWriteType.PIPE_READ_WRITE
return self
@@ -1107,10 +1136,8 @@ def command(f=None, dtype_in=None, dformat_in=None, doc_in="",
class _BaseProperty(object):
-
def __init__(self, dtype, doc='', default_value=None, update_db=False):
self.name = None
- self.__value = None
dtype = from_typeformat_to_type(*_get_tango_type_format(dtype))
self.dtype = dtype
self.doc = doc
@@ -1147,9 +1174,11 @@ class device_property(_BaseProperty):
class PowerSupply(Device):
host = device_property(dtype=str)
+ port = device_property(dtype=int, mandatory=True)
:param dtype: Data type (see :ref:`pytango-data-types`)
:param doc: property documentation (optional)
+ :param mandatory (optional: default is False)
:param default_value: default value for the property (optional)
:param update_db: tells if set value should write the value to database.
[default: False]
@@ -1158,7 +1187,15 @@ class device_property(_BaseProperty):
.. versionadded:: 8.1.7
added update_db option
"""
- pass
+ def __init__(self, dtype, doc='', mandatory=False,
+ default_value=None, update_db=False):
+ super(device_property, self).__init__(dtype, doc, default_value,
+ update_db)
+ self.mandatory = mandatory
+ if mandatory and default_value is not None:
+ msg = "device_property arguments mandatory " \
+ "and default_value are incompatible"
+ raise Exception(msg)
class class_property(_BaseProperty):
@@ -1262,15 +1299,9 @@ def __server_run(classes, args=None, msg_stream=sys.stdout, util=None,
event_loop=None, post_init_callback=None,
green_mode=None):
if green_mode is None:
- from tango import get_green_mode
green_mode = get_green_mode()
- async_mode = green_mode in (GreenMode.Gevent, GreenMode.Asyncio)
- import tango
- if msg_stream is None:
- write = lambda msg: None
- else:
- write = msg_stream.write
+ write = msg_stream.write if msg_stream else lambda msg: None
if args is None:
args = sys.argv
@@ -1278,18 +1309,16 @@ def __server_run(classes, args=None, msg_stream=sys.stdout, util=None,
post_init_callback = __to_cb(post_init_callback)
if util is None:
- util = tango.Util(args)
+ util = Util(args)
- if async_mode:
- util.set_serial_model(tango.SerialModel.NO_SYNC)
- worker = _create_async_worker(green_mode)
- set_worker(worker)
+ if green_mode in (GreenMode.Gevent, GreenMode.Asyncio):
+ util.set_serial_model(SerialModel.NO_SYNC)
- worker = get_worker()
+ worker = get_executor(green_mode)
+ set_worker(worker)
if event_loop is not None:
- if async_mode:
- event_loop = functools.partial(worker.execute, event_loop)
+ event_loop = functools.partial(worker.execute, event_loop)
util.server_set_event_loop(event_loop)
log = logging.getLogger("tango")
@@ -1301,22 +1330,16 @@ def __server_run(classes, args=None, msg_stream=sys.stdout, util=None,
worker.execute(post_init_callback)
write("Ready to accept request\n")
util.server_run()
- worker.stop()
log.debug("server loop exit")
- if async_mode:
- task = worker.run_in_thread(tango_loop)
- worker.run(task)
- log.debug("async worker finished")
- else:
- tango_loop()
-
+ worker.run(tango_loop, wait=True)
return util
def run(classes, args=None, msg_stream=sys.stdout,
verbose=False, util=None, event_loop=None,
- post_init_callback=None, green_mode=None):
+ post_init_callback=None, green_mode=None,
+ raises=False):
"""
Provides a simple way to run a tango server. It handles exceptions
by writting a message to the msg_stream.
@@ -1425,6 +1448,10 @@ def run(classes, args=None, msg_stream=sys.stdout,
:type post_init_callback:
callable or tuple (see description above)
+ :param raises:
+ Disable error handling and propagate exceptions from the server
+ :type raises: bool
+
:return: The Util singleton object
:rtype: :class:`~tango.Util`
@@ -1433,16 +1460,23 @@ def run(classes, args=None, msg_stream=sys.stdout,
.. versionchanged:: 8.1.4
when classes argument is a sequence, the items can also be
a sequence <TangoClass, TangoClassClass>[, tango class name]
+
+ .. versionchanged:: 9.2.2
+ `raises` argument has been added
"""
- if msg_stream is None:
- write = lambda msg: None
- else:
- write = msg_stream.write
+ server_run = functools.partial(
+ __server_run, classes,
+ args=args, msg_stream=msg_stream,
+ util=util, event_loop=event_loop,
+ post_init_callback=post_init_callback,
+ green_mode=green_mode)
+ # Run the server without error handling
+ if raises:
+ return server_run()
+ # Run the server with error handling
+ write = msg_stream.write if msg_stream else lambda msg: None
try:
- return __server_run(classes, args=args, msg_stream=msg_stream,
- util=util, event_loop=event_loop,
- post_init_callback=post_init_callback,
- green_mode=green_mode)
+ return server_run()
except KeyboardInterrupt:
write("Exiting: Keyboard interrupt\n")
except DevFailed as df:
@@ -1490,207 +1524,12 @@ def server_run(classes, args=None, msg_stream=sys.stdout,
green_mode=green_mode)
-class BaseWorker:
- def __init__(self, max_queue_size=0):
- pass
-
- def execute(self, func, *args, **kwargs):
- return func(*args, **kwargs)
-
- def stop(self):
- pass
-
-
-__WORKER = BaseWorker()
-__ASYNC_WORKER = None
-
-def get_worker():
- global __WORKER
- return __WORKER
-
-
-def set_worker(worker):
- global __WORKER
- __WORKER = worker
-
-
-def get_async_worker():
- global __ASYNC_WORKER
- return __ASYNC_WORKER
-
-
-def _create_async_worker(green_mode):
- global __ASYNC_WORKER
- if __ASYNC_WORKER:
- return __ASYNC_WORKER
- if green_mode == GreenMode.Gevent:
- _ASYNC_WORKER = _create_gevent_worker()
- if green_mode == GreenMode.Asyncio:
- _ASYNC_WORKER = _create_asyncio_worker()
- return _ASYNC_WORKER
-
-
-def _create_gevent_worker():
- try:
- from queue import Queue
- except:
- from Queue import Queue
- from threading import current_thread
-
- import gevent
- import gevent.event
- import gevent._threading
-
- class GeventWorker(BaseWorker):
-
- class Task:
-
- def __init__(self, event, func, *args, **kwargs):
- self.__event = event
- self.__func = func
- self.__args = args
- self.__kwargs = kwargs
- self.value = None
- self.exception = None
-
- def __call__(self):
- func = self.__func
- if func:
- try:
- self.value = func(*self.__args, **self.__kwargs)
- except:
- self.exception = sys.exc_info()
- self.__event.set()
-
- def run(self):
- return gevent.spawn(self)
-
- def __init__(self, max_queue_size=0):
- self.__tasks = Queue(max_queue_size)
- self.__stop_event = gevent.event.Event()
- self.__watcher = gevent.get_hub().loop.async()
- self.__watcher.start(self.__step)
- self.__lock = gevent._threading.Lock()
- self.__id = id(current_thread())
-
- def __step(self):
- task = self.__tasks.get()
- return task.run()
-
- def is_gevent_thread(self):
- return self.__id == id(current_thread())
-
- def run_in_thread(self, func, *args, **kwargs):
- return gevent.get_hub().threadpool.spawn(func, *args, **kwargs)
-
- def run(self, until=None, timeout=None):
- if until is not None:
- objects = until, self.__stop_event
- else:
- objects = self.__stop_event,
- return gevent.wait(objects=objects, timeout=timeout)
-
- def execute(self, func, *args, **kwargs):
- if self.is_gevent_thread():
- return func(*args, **kwargs)
- event = gevent._threading.Event()
- task = self.Task(event, func, *args, **kwargs)
- with self.__lock:
- self.__tasks.put(task)
- self.__watcher.send()
- event.wait()
- if task.exception:
- if issubclass(task.exception[0], DevFailed):
- raise task.exception[1]
- else:
- Except.throw_python_exception(*task.exception)
- return task.value
-
- def stop(self):
- task = self.Task(self.__stop_event, None)
- self.__tasks.put(task)
- self.__watcher.send()
-
- return GeventWorker()
-
-
-def _create_asyncio_worker():
- import concurrent.futures
-
- try:
- from threading import get_ident
- except:
- from threading import _get_ident as get_ident
-
- try:
- import asyncio
- except ImportError:
- import trollius as asyncio
-
- try:
- from asyncio import run_coroutine_threadsafe
- except ImportError:
- from .asyncio_tools import run_coroutine_threadsafe
-
- class LoopExecutor(concurrent.futures.Executor):
- """An Executor subclass that uses an event loop
- to execute calls asynchronously."""
-
- def __init__(self, loop=None):
- """Initialize the executor with a given loop."""
- self.loop = loop or asyncio.get_event_loop()
-
- def submit(self, corofn, *args, **kwargs):
- """Schedule a coroutine, to be executed as corofn(*args **kwargs).
- Return a Future representing the execution of the callable."""
- return run_coroutine_threadsafe(corofn(*args, **kwargs), self.loop)
-
- def run_in_thread(self, func, *args, **kwargs):
- """Schedule a blocking callback."""
- callback = lambda: func(*args, **kwargs)
- coro = self.loop.run_in_executor(None, callback)
- # That is not actually necessary since coro is actually
- # a future. But it is an implementation detail and it
- # might be changed later on.
- return asyncio.async(coro)
-
- def run(self, until=None, timeout=None):
- """Run the asyncio event loop."""
- if until is None and timeout is None:
- return self.loop.run_forever()
- if until is None:
- until = asyncio.sleep(timeout, loop=self.loop)
- return self.loop.run_until_complete(until)
-
- def stop(self):
- """Run the asyncio event loop."""
- self.loop.stop()
-
- def execute(self, fn, *args, **kwargs):
- """Execute the callable fn as fn(*args **kwargs)."""
- corofn = asyncio.coroutine(lambda: fn(*args, **kwargs))
- if self.loop._thread_id == get_ident():
- return corofn()
- return self.submit(corofn).result()
-
- try:
- loop = asyncio.get_event_loop()
- except RuntimeError:
- loop = asyncio.new_event_loop()
- asyncio.set_event_loop(loop)
- return LoopExecutor(loop=loop)
-
-
# Instanciate DeviceMeta using BaseDevice
-@six.add_metaclass(DeviceMeta)
-class Device(BaseDevice):
- """
+Device = DeviceMeta("Device", (BaseDevice,), {'__doc__': """\
Device class for the high-level API.
All device specific classes should inherit from this class.
- """
- pass
-
+ """})
# Avoid circular imports
-from .tango_object import Server
+from .tango_object import Server # noqa: E402
diff --git a/tango/tango_asyncio.py b/tango/tango_asyncio.py
deleted file mode 100644
index 740a569..0000000
--- a/tango/tango_asyncio.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# -----------------------------------------------------------------------------
-# This file is part of PyTango (http://pytango.rtfd.io)
-#
-# Copyright 2006-2012 CELLS / ALBA Synchrotron, Bellaterra, Spain
-# Copyright 2013-2014 European Synchrotron Radiation Facility, Grenoble, France
-#
-# Distributed under the terms of the GNU Lesser General Public License,
-# either version 3 of the License, or (at your option) any later version.
-# See LICENSE.txt for more info.
-# -----------------------------------------------------------------------------
-
-from __future__ import absolute_import
-
-__all__ = ["get_global_executor", "submit", "spawn", "wait", "get_event_loop"]
-
-__global_executor = None
-
-
-def __get_executor_class():
- # Imports
- import concurrent.futures
- from functools import partial
- try:
- import asyncio
- except ImportError:
- import trollius as asyncio
-
- # Asyncio executor
- class AsyncioExecutor(concurrent.futures.Executor):
- """Executor to submit task to a subexecutor through an asyncio loop.
- Warning: This class has nothing to do with the AsyncioExecutor class
- implemented for the server.
- """
-
- def __init__(self, loop=None, subexecutor=None):
- self.subexecutor = subexecutor
- self.loop = loop or asyncio.get_event_loop()
-
- def submit(self, fn, *args, **kwargs):
- callback = partial(fn, *args, **kwargs)
- return self.loop.run_in_executor(self.subexecutor, callback)
-
- # Return
- return AsyncioExecutor
-
-
-def get_global_executor():
- # Get global executor
- global __global_executor
- if __global_executor is not None:
- return __global_executor
- # Import futures executor
- try:
- from .tango_futures import get_global_executor as get_futures_executor
- except ImportError:
- get_futures_executor = lambda: None
- # Set global
- loop = get_event_loop()
- klass = __get_executor_class()
- subexecutor = get_futures_executor()
- __global_executor = klass(loop, subexecutor)
- return __global_executor
-
-
-def submit(fn, *args, **kwargs):
- return get_global_executor().submit(fn, *args, **kwargs)
-
-spawn = submit
-
-
-def wait(fut, timeout=None, loop=None):
- # Imports
- try:
- import asyncio
- except ImportError:
- import trollius as asyncio
- # Run loop
- loop = loop or asyncio.get_event_loop()
- coro = asyncio.wait_for(fut, timeout, loop=loop)
- return loop.run_until_complete(coro)
-
-
-def get_event_loop():
- # Imports
- try:
- import asyncio
- except ImportError:
- import trollius as asyncio
- # Get loop
- global __event_loop
- if __event_loop is not None:
- return __event_loop
- # Create loop
- try:
- loop = asyncio.get_event_loop()
- except RuntimeError:
- loop = asyncio.new_event_loop()
- asyncio.set_event_loop(loop)
-
- def submit(fn, *args, **kwargs):
- callback = lambda: fn(*args, **kwargs)
- return loop.call_soon_threadsafe(callback)
-
- # Patch loop
- loop.submit = submit
- __event_loop = loop
- return loop
-
-
-__event_loop = None
diff --git a/tango/tango_futures.py b/tango/tango_futures.py
deleted file mode 100644
index 04d00d6..0000000
--- a/tango/tango_futures.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# ------------------------------------------------------------------------------
-# This file is part of PyTango (http://pytango.rtfd.io)
-#
-# Copyright 2006-2012 CELLS / ALBA Synchrotron, Bellaterra, Spain
-# Copyright 2013-2014 European Synchrotron Radiation Facility, Grenoble, France
-#
-# Distributed under the terms of the GNU Lesser General Public License,
-# either version 3 of the License, or (at your option) any later version.
-# See LICENSE.txt for more info.
-# ------------------------------------------------------------------------------
-
-__all__ = ["get_global_executor", "submit", "spawn", "wait"]
-
-__global_executor = None
-
-MAX_WORKERS = 8
-MODE = 'thread'
-
-
-def __get_executor_class():
- import concurrent.futures
- ret = None
- if MODE == 'thread':
- ret = concurrent.futures.ThreadPoolExecutor
- else:
- ret = concurrent.futures.ProcessPoolExecutor
- return ret
-
-
-def get_global_executor():
- global __global_executor
- if __global_executor is None:
- klass = __get_executor_class()
- if klass is not None:
- __global_executor = klass(max_workers=MAX_WORKERS)
- return __global_executor
-
-
-def submit(fn, *args, **kwargs):
- return get_global_executor().submit(fn, *args, **kwargs)
-
-
-def wait(fut, timeout=None):
- return fut.result(timeout=timeout)
-
-
-spawn = submit
diff --git a/tango/tango_gevent.py b/tango/tango_gevent.py
deleted file mode 100644
index 3876a39..0000000
--- a/tango/tango_gevent.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# ------------------------------------------------------------------------------
-# This file is part of PyTango (http://pytango.rtfd.io)
-#
-# Copyright 2006-2012 CELLS / ALBA Synchrotron, Bellaterra, Spain
-# Copyright 2013-2014 European Synchrotron Radiation Facility, Grenoble, France
-#
-# Distributed under the terms of the GNU Lesser General Public License,
-# either version 3 of the License, or (at your option) any later version.
-# See LICENSE.txt for more info.
-# ------------------------------------------------------------------------------
-
-from __future__ import absolute_import
-import sys
-import types
-
-import six
-
-__all__ = ["get_global_threadpool", "get_global_executor",
- "get_event_loop", "submit", "spawn", "wait"]
-
-
-def get_global_threadpool():
- import gevent
- thread_pool = gevent.get_hub().threadpool
- # before gevent-1.1.0, patch the spawn method to propagate exception raised
- # in the loop to the AsyncResult.
- if gevent.version_info < (1, 1):
- thread_pool.submit = patched_spawn
- else:
- thread_pool.submit = thread_pool.spawn
- return thread_pool
-
-
-class ExceptionWrapper:
- def __init__(self, exception, error_string, tb):
- self.exception = exception
- self.error_string = error_string
- self.tb = tb
-
-
-class wrap_errors(object):
- def __init__(self, func):
- """Make a new function from `func', such that it catches all exceptions
- and return it as a specific object
- """
- self.func = func
-
- def __call__(self, *args, **kwargs):
- func = self.func
- try:
- return func(*args, **kwargs)
- except:
- return ExceptionWrapper(*sys.exc_info())
-
- def __str__(self):
- return str(self.func)
-
- def __repr__(self):
- return repr(self.func)
-
- def __getattr__(self, item):
- return getattr(self.func, item)
-
-
-def get_with_exception(g, block=True, timeout=None):
- result = g._get(block, timeout)
- if isinstance(result, ExceptionWrapper):
- # raise the exception using the caller context
- six.reraise(result.exception, result.error_string, result.tb)
- else:
- return result
-
-
-def patched_spawn(fn, *args, **kwargs):
- # the gevent threadpool do not raise exception with asyncresults,
- # we have to wrap it
- fn = wrap_errors(fn)
- g = get_global_threadpool().spawn(fn, *args, **kwargs)
- g._get = g.get
- g.get = types.MethodType(get_with_exception, g)
- return g
-
-
-def spawn(fn, *args, **kwargs):
- return get_global_threadpool().submit(fn, *args, **kwargs)
-
-
-get_global_executor = get_global_threadpool
-submit = spawn
-__event_loop = None
-
-
-def get_event_loop():
- global __event_loop
- if __event_loop is None:
- import gevent
- import gevent.queue
-
- def loop(queue):
- while True:
- item = queue.get()
- try:
- f, args, kwargs = item
- gevent.spawn(f, *args, **kwargs)
- except Exception as e:
- sys.excepthook(*sys.exc_info())
-
- def submit(fn, *args, **kwargs):
- l_async = queue.hub.loop.async()
- queue.put((fn, args, kwargs))
- l_async.send()
-
- queue = gevent.queue.Queue()
- __event_loop = gevent.spawn(loop, queue)
- __event_loop.submit = submit
- return __event_loop
-
-
-def wait(greenlet, timeout=None):
- return greenlet.get(timeout=timeout)
diff --git a/tango/tango_numpy.py b/tango/tango_numpy.py
index d7a8140..7615619 100644
--- a/tango/tango_numpy.py
+++ b/tango/tango_numpy.py
@@ -13,16 +13,17 @@
This is an internal PyTango module.
"""
-__all__ = [ "NumpyType", "numpy_type", "numpy_spectrum", "numpy_image" ]
+__all__ = ["NumpyType", "numpy_type", "numpy_spectrum", "numpy_image"]
__docformat__ = "restructuredtext"
-from ._tango import Except
-from ._tango import constants
+from ._tango import Except, Attribute, AttributeInfo, constants
+from ._tango import CmdArgType as ArgType
from .attribute_proxy import AttributeProxy
import collections
+
def _numpy_invalid(*args, **kwds):
Except.throw_exception(
"PyTango_InvalidConversion",
@@ -30,17 +31,13 @@ def _numpy_invalid(*args, **kwds):
"NumpyType.tango_to_numpy"
)
+
def _define_numpy():
if not constants.NUMPY_SUPPORT:
return None, _numpy_invalid, _numpy_invalid, _numpy_invalid
-
+
try:
import numpy
- import operator
-
- ArgType = _tango.CmdArgType
- AttributeInfo = _tango.AttributeInfo
- Attribute = _tango.Attribute
class NumpyType(object):
@@ -72,7 +69,7 @@ def _define_numpy():
def tango_to_numpy(param):
if isinstance(param, ArgType):
tg_type = param
- if isinstance(param, AttributeInfo): # or AttributeInfoEx
+ if isinstance(param, AttributeInfo): # or AttributeInfoEx
tg_type = param.data_type
elif isinstance(param, Attribute):
tg_type = param.get_data_type()
@@ -134,11 +131,13 @@ def _define_numpy():
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)
-
- return NumpyType, NumpyType.spectrum, \
- NumpyType.image, NumpyType.tango_to_numpy
+ return numpy.ndarray(shape=(dim_y, dim_x,), dtype=np_type)
+
+ return (
+ NumpyType, NumpyType.spectrum,
+ NumpyType.image, NumpyType.tango_to_numpy)
except Exception:
return None, _numpy_invalid, _numpy_invalid, _numpy_invalid
+
NumpyType, numpy_spectrum, numpy_image, numpy_type = _define_numpy()
diff --git a/tango/tango_object.py b/tango/tango_object.py
index 08abb89..825b1f4 100644
--- a/tango/tango_object.py
+++ b/tango/tango_object.py
@@ -24,12 +24,12 @@ from .attr_data import AttrData
from .utils import TO_TANGO_TYPE
from ._tango import AttrDataFormat, CmdArgType, GreenMode
from ._tango import DbDevInfo, Database, DevState, constants
-from .server import Device, DeviceMeta, _to_classes, _add_classes
-from .server import _create_async_worker, get_worker, set_worker
+from .server import Device, _to_classes, _add_classes
+from .server import get_worker, set_worker
+from .green import get_executor
__all__ = ['Server']
-
_CLEAN_UP_TEMPLATE = """
import sys
from tango import Database
@@ -64,11 +64,11 @@ def __to_tango_type_fmt(value):
shape_l = len(value.shape)
if shape_l == 1:
dfmt = AttrDataFormat.SPECTRUM
- max_dim_x = max(2**16, value.shape[0])
+ max_dim_x = max(2 ** 16, value.shape[0])
elif shape_l == 2:
dfmt = AttrDataFormat.IMAGE
- max_dim_x = max(2**16, value.shape[0])
- max_dim_y = max(2**16, value.shape[1])
+ max_dim_x = max(2 ** 16, value.shape[0])
+ max_dim_y = max(2 ** 16, value.shape[1])
else:
dtype = CmdArgType.DevEncoded
return dtype, dfmt, max_dim_x, max_dim_y
@@ -200,9 +200,7 @@ def create_tango_class(server, obj, tango_class_name=None, member_filter=None):
pars = dict(name=name, dtype=dtype, dformat=fmt,
max_dim_x=x, max_dim_y=y, fget=read)
- if read_only:
- write = None
- else:
+ if not read_only:
write.__name__ = "_write_" + name
pars['fset'] = write
setattr(DeviceDispatcher, write.__name__, write)
@@ -273,7 +271,7 @@ class Server:
self.__tango_classes = _to_classes(tango_classes or [])
self.__tango_devices = []
if self.async_mode:
- self.__worker = _create_async_worker(self.green_mode)
+ self.__worker = get_executor(self.green_mode)
else:
self.__worker = get_worker()
set_worker(self.__worker)
@@ -319,9 +317,9 @@ class Server:
except:
self.log.info("Last time server was not properly "
"shutdown!")
- db_class_map, db_device_map = self.get_devices()
+ _, db_device_map = self.get_devices()
else:
- db_class_map, db_device_map = {}, {}
+ db_device_map = {}
db_devices_add = {}
@@ -398,14 +396,8 @@ class Server:
_add_classes(util, self.__tango_classes)
- if async_mode:
- tango_thread_id = self.worker.run_in_thread(self.__tango_loop)
-
def __run(self, timeout=None):
- if self.async_mode:
- return self.worker.run(timeout=timeout)
- else:
- self.__tango_loop()
+ return self.worker.run(self.__tango_loop, wait=True, timeout=timeout)
def __tango_loop(self):
self.log.debug("server loop started")
@@ -415,7 +407,6 @@ class Server:
self._phase = Server.Phase2
self.log.info("Ready to accept request")
u_instance.server_run()
- self.worker.stop()
if self.__auto_clean:
self.__clean_up_process()
self.log.debug("server loop exit")
@@ -516,10 +507,8 @@ class Server:
def register_tango_device(self, klass, name):
if inspect.isclass(klass):
if isinstance(klass, Device):
- kk, Device.TangoClassClass
- k = Device
- kname = Device.TangoClassName
- # TODO: ??
+ # TODO
+ raise NotImplementedError
else:
raise ValueError
else:
diff --git a/tango/test_context.py b/tango/test_context.py
index da58f3d..c02aa87 100644
--- a/tango/test_context.py
+++ b/tango/test_context.py
@@ -4,11 +4,14 @@ from __future__ import absolute_import
# Imports
import os
+import sys
import six
+import time
import struct
import socket
import tempfile
import collections
+from functools import partial
# Concurrency imports
import threading
@@ -26,7 +29,6 @@ from . import DeviceProxy, Database, Util
__all__ = ["DeviceTestContext", "run_device_test_context"]
-
# Helpers
IOR = collections.namedtuple(
@@ -37,7 +39,7 @@ IOR = collections.namedtuple(
def ascii_to_bytes(s):
convert = lambda x: six.int2byte(int(x, 16))
- return b''.join(convert(s[i:i+2]) for i in range(0, len(s), 2))
+ return b''.join(convert(s[i:i + 2]) for i in range(0, len(s), 2))
def parse_ior(encoded_ior):
@@ -75,7 +77,7 @@ def device(path):
def get_hostname():
"""Get the hostname corresponding to the primary, external IP.
- This is useful becauce an explicit hostname is required to get
+ This is useful because an explicit hostname is required to get
tango events to work properly. Note that localhost does not work
either.
"""
@@ -95,13 +97,14 @@ class DeviceTestContext(object):
nodb = "dbase=no"
command = "{0} {1} -ORBendPoint giop:tcp:{2}:{3} -file={4}"
- connect_timeout = 1.
- disconnect_timeout = connect_timeout
+
+ thread_timeout = 3.
+ process_timeout = 5.
def __init__(self, device, device_cls=None, server_name=None,
- instance_name=None, device_name=None, properties={},
+ instance_name=None, device_name=None, properties=None,
db=None, host=None, port=0, debug=3,
- process=False, daemon=False):
+ process=False, daemon=False, timeout=None):
"""Inititalize the context to run a given device."""
# Argument
tangoclass = device.__name__
@@ -115,6 +118,10 @@ class DeviceTestContext(object):
_, db = tempfile.mkstemp()
if host is None:
host = get_hostname()
+ if properties is None:
+ properties = {}
+ if timeout is None:
+ timeout = self.process_timeout if process else self.thread_timeout
# Patch bug #819
if process:
os.environ['ORBscanGranularity'] = '0'
@@ -122,6 +129,7 @@ class DeviceTestContext(object):
self.db = db
self.host = host
self.port = port
+ self.timeout = timeout
self.device_name = device_name
self.server_name = "/".join(("dserver", server_name, instance_name))
self.device = self.server = None
@@ -136,23 +144,47 @@ class DeviceTestContext(object):
cmd_args = string.split()
# Target and arguments
if device_cls:
- target = run
- args = ({tangoclass: (device_cls, device)}, cmd_args)
+ class_dct = {tangoclass: (device_cls, device)}
+ runserver = partial(run, class_dct, cmd_args)
elif not hasattr(device, 'run_server'):
- target = run
- args = ((device,), cmd_args)
+ runserver = partial(run, (device,), cmd_args)
else:
- target = device.run_server
- args = (cmd_args,)
+ runserver = partial(device.run_server, cmd_args)
# Thread
- kwargs = {'post_init_callback': self.post_init}
cls = multiprocessing.Process if process else threading.Thread
- self.thread = cls(target=target, args=args, kwargs=kwargs)
+ self.thread = cls(target=self.target, args=(runserver, process))
self.thread.daemon = daemon
+ def target(self, runserver, process=False):
+ try:
+ runserver(post_init_callback=self.post_init, raises=True)
+ except Exception:
+ # Put exception in the queue
+ etype, value, tb = sys.exc_info()
+ if process:
+ tb = None # Traceback objects can't be pickled
+ self.queue.put((etype, value, tb))
+ finally:
+ # Put something in the queue just in case
+ exc = RuntimeError("The server failed to report anything")
+ self.queue.put((None, exc, None))
+ # Make sure the process has enough time to send the items
+ # because the it might segfault while cleaning up the
+ # the tango resources
+ if process:
+ time.sleep(0.01)
+
def post_init(self):
- host, port = get_server_host_port()
- self.queue.put((host, port))
+ try:
+ host, port = get_server_host_port()
+ self.queue.put((host, port))
+ except Exception as exc:
+ self.queue.put((None, exc, None))
+ finally:
+ # Put something in the queue just in case
+ exc = RuntimeError(
+ "The post_init routine failed to report anything")
+ self.queue.put((None, exc, None))
def generate_db_file(self, server, instance, device,
tangoclass=None, properties={}):
@@ -190,12 +222,26 @@ class DeviceTestContext(object):
def connect(self):
try:
- self.host, self.port = self.queue.get(
- timeout=self.connect_timeout)
+ args = self.queue.get(
+ timeout=self.timeout)
except queue.Empty:
- raise RuntimeError(
- 'The server did not start. '
- 'Check stdout/stderr for more information.')
+ if self.thread.is_alive():
+ raise RuntimeError(
+ 'The server appears to be stuck at initialization. '
+ 'Check stdout/stderr for more information.')
+ elif hasattr(self.thread, 'exitcode'):
+ raise RuntimeError(
+ 'The server process stopped with exitcode {}. '
+ 'Check stdout/stderr for more information.'
+ ''.format(self.thread.exitcode))
+ else:
+ raise RuntimeError(
+ 'The server stopped without reporting. '
+ 'Check stdout/stderr for more information.')
+ try:
+ self.host, self.port = args
+ except ValueError:
+ six.reraise(*args)
# Get server proxy
self.server = DeviceProxy(self.get_server_access())
self.server.ping()
@@ -205,10 +251,12 @@ class DeviceTestContext(object):
def stop(self):
"""Kill the server."""
- if self.server:
- self.server.command_inout('Kill')
- self.join(self.disconnect_timeout)
- os.unlink(self.db)
+ try:
+ if self.server:
+ self.server.command_inout('Kill')
+ self.join(self.timeout)
+ finally:
+ os.unlink(self.db)
def join(self, timeout=None):
self.thread.join(timeout)
diff --git a/tango/test_utils.py b/tango/test_utils.py
index 25092c6..3f43933 100644
--- a/tango/test_utils.py
+++ b/tango/test_utils.py
@@ -1,8 +1,7 @@
"""Test utilities"""
# Local imports
-from . import utils
-from . import DevState, CmdArgType, GreenMode
+from . import DevState, GreenMode
from .server import Device
from .test_context import DeviceTestContext
@@ -12,6 +11,11 @@ try:
except ImportError:
pytest = None
+try:
+ import numpy.testing
+except ImportError:
+ numpy = None
+
__all__ = ['DeviceTestContext', 'SimpleDevice']
@@ -22,6 +26,35 @@ class SimpleDevice(Device):
self.set_state(DevState.ON)
+# Helpers
+
+TYPED_VALUES = {
+ int: (1, 2),
+ float: (2.71, 3.14),
+ str: ('hey hey', 'my my'),
+ bool: (False, True),
+ (int,): ([1, 2, 3], [9, 8, 7]),
+ (float,): ([0.1, 0.2, 0.3], [0.9, 0.8, 0.7]),
+ (str,): (['ab', 'cd', 'ef'], ['gh', 'ij', 'kl']),
+ (bool,): ([False, False, True], [True, False, False])}
+
+
+def repr_type(x):
+ if not isinstance(x, tuple):
+ return x.__name__
+ return '({},)'.format(x[0].__name__)
+
+
+# Numpy helpers
+
+if numpy and pytest:
+
+ def assert_close(a, b):
+ try:
+ assert a == pytest.approx(b)
+ except ValueError:
+ numpy.testing.assert_allclose(a, b)
+
# Pytest fixtures
if pytest:
@@ -30,22 +63,11 @@ if pytest:
def state(request):
return request.param
- @pytest.fixture(params=utils._scalar_types)
+ @pytest.fixture(
+ params=list(TYPED_VALUES.items()),
+ ids=lambda x: repr_type(x[0]))
def typed_values(request):
- dtype = request.param
- # Unsupported types
- if dtype in [CmdArgType.DevInt, CmdArgType.ConstDevString,
- CmdArgType.DevEncoded, CmdArgType.DevUChar]:
- pytest.xfail('Should we support those types?')
- # Supported types
- if dtype in utils._scalar_str_types:
- return dtype, ['hey hey', 'my my']
- if dtype in utils._scalar_bool_types:
- return dtype, [False, True]
- if dtype in utils._scalar_int_types:
- return dtype, [1, 2]
- if dtype in utils._scalar_float_types:
- return dtype, [2.71, 3.14]
+ return request.param
@pytest.fixture(params=GreenMode.values.values())
def green_mode(request):
diff --git a/tango/time_val.py b/tango/time_val.py
index c8a9e7f..4539a67 100644
--- a/tango/time_val.py
+++ b/tango/time_val.py
@@ -19,19 +19,19 @@ __docformat__ = "restructuredtext"
import time
import datetime
-import operator
from ._tango import TimeVal
import numbers
+
def __TimeVal__init(self, a=None, b=None, c=None):
TimeVal.__init_original(self)
- if a is None:
+ 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
+ assert (b is None and c is None)
+ a = time.mktime(a.timetuple()) + a.microsecond * 1E-6
elif isinstance(a, numbers.Number):
if b is None:
@@ -42,56 +42,60 @@ def __TimeVal__init(self, a=None, b=None, c=None):
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
+ 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:`tango.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:`tango.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
@@ -99,16 +103,17 @@ def __TimeVal__fromdatetime(dt):
"""
return TimeVal(dt)
+
def __TimeVal__now():
"""
now() -> TimeVal
A static method returning a :class:`tango.TimeVal` object representing
the current time
-
+
Parameters : None
Return : (TimeVal) representing the current time
-
+
.. versionadded:: 7.1.0
.. versionadded:: 7.1.2
@@ -116,16 +121,17 @@ def __TimeVal__now():
"""
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 :
+
+ 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
@@ -133,35 +139,37 @@ def __TimeVal__strftime(self, format):
"""
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 :
+
+ 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
@@ -169,6 +177,7 @@ def __TimeVal__str__(self):
"""
return str(self.todatetime())
+
def __init_TimeVal():
TimeVal.__init_original = TimeVal.__init__
TimeVal.__init__ = __TimeVal__init
@@ -180,7 +189,7 @@ def __init_TimeVal():
TimeVal.strftime = __TimeVal__strftime
TimeVal.isoformat = __TimeVal__isoformat
TimeVal.__str__ = __TimeVal__str__
-
+
+
def time_val_init(doc=True):
__init_TimeVal()
-
diff --git a/tango/utils.py b/tango/utils.py
index a1747ec..bae8b6f 100644
--- a/tango/utils.py
+++ b/tango/utils.py
@@ -26,7 +26,7 @@ import collections
from ._tango import StdStringVector, StdDoubleVector, \
DbData, DbDevInfos, DbDevExportInfos, CmdArgType, AttrDataFormat, \
EventData, AttrConfEventData, DataReadyEventData, DevFailed, constants, \
- DevState, CommunicationFailed
+ DevState, CommunicationFailed, PipeEventData, DevIntrChangeEventData
from . import _tango
from .constants import AlrmValueNotSpec, StatusNotSet, TgLibVers
@@ -36,7 +36,7 @@ __all__ = [
"requires_pytango", "requires_tango",
"is_pure_str", "is_seq", "is_non_str_seq", "is_integer",
"is_number", "is_scalar_type", "is_array_type", "is_numerical_type",
- "is_int_type", "is_float_type", "is_bool_type", "is_bin_type",
+ "is_int_type", "is_float_type", "is_bool_type", "is_binary_type",
"is_str_type", "obj_2_str", "seqStr_2_obj",
"scalar_to_array_type",
"document_method", "document_static_method", "document_enum",
@@ -47,7 +47,6 @@ __all__ = [
__docformat__ = "restructuredtext"
-
# Types
_scalar_int_types = (
@@ -118,40 +117,40 @@ _binary_types = (
def __build_to_tango_type():
ret = {
- int : CmdArgType.DevLong64,
- str : CmdArgType.DevString,
- bool : CmdArgType.DevBoolean,
- bytearray : CmdArgType.DevEncoded,
- float : CmdArgType.DevDouble,
- chr : CmdArgType.DevUChar,
- None : CmdArgType.DevVoid,
-
- 'int' : CmdArgType.DevLong64,
- 'int16' : CmdArgType.DevShort,
- 'int32' : CmdArgType.DevLong,
- 'int64' : CmdArgType.DevLong64,
- 'uint' : CmdArgType.DevULong64,
- 'uint16' : CmdArgType.DevUShort,
- 'uint32' : CmdArgType.DevULong,
- 'uint64' : CmdArgType.DevULong64,
- 'str' : CmdArgType.DevString,
- 'string' : CmdArgType.DevString,
- 'text' : CmdArgType.DevString,
- 'bool' : CmdArgType.DevBoolean,
- 'boolean' : CmdArgType.DevBoolean,
- 'bytes' : CmdArgType.DevEncoded,
- 'bytearray' : CmdArgType.DevEncoded,
- 'float' : CmdArgType.DevDouble,
- 'float32' : CmdArgType.DevFloat,
- 'float64' : CmdArgType.DevDouble,
- 'double' : CmdArgType.DevDouble,
- 'byte' : CmdArgType.DevUChar,
- 'chr' : CmdArgType.DevUChar,
- 'char' : CmdArgType.DevUChar,
- 'None' : CmdArgType.DevVoid,
- 'state' : CmdArgType.DevState,
- 'enum' : CmdArgType.DevEnum,
- 'blob' : CmdArgType.DevPipeBlob,
+ int: CmdArgType.DevLong64,
+ str: CmdArgType.DevString,
+ bool: CmdArgType.DevBoolean,
+ bytearray: CmdArgType.DevEncoded,
+ float: CmdArgType.DevDouble,
+ chr: CmdArgType.DevUChar,
+ None: CmdArgType.DevVoid,
+
+ 'int': CmdArgType.DevLong64,
+ 'int16': CmdArgType.DevShort,
+ 'int32': CmdArgType.DevLong,
+ 'int64': CmdArgType.DevLong64,
+ 'uint': CmdArgType.DevULong64,
+ 'uint16': CmdArgType.DevUShort,
+ 'uint32': CmdArgType.DevULong,
+ 'uint64': CmdArgType.DevULong64,
+ 'str': CmdArgType.DevString,
+ 'string': CmdArgType.DevString,
+ 'text': CmdArgType.DevString,
+ 'bool': CmdArgType.DevBoolean,
+ 'boolean': CmdArgType.DevBoolean,
+ 'bytes': CmdArgType.DevEncoded,
+ 'bytearray': CmdArgType.DevEncoded,
+ 'float': CmdArgType.DevDouble,
+ 'float32': CmdArgType.DevFloat,
+ 'float64': CmdArgType.DevDouble,
+ 'double': CmdArgType.DevDouble,
+ 'byte': CmdArgType.DevUChar,
+ 'chr': CmdArgType.DevUChar,
+ 'char': CmdArgType.DevUChar,
+ 'None': CmdArgType.DevVoid,
+ 'state': CmdArgType.DevState,
+ 'enum': CmdArgType.DevEnum,
+ 'blob': CmdArgType.DevPipeBlob,
}
try:
@@ -184,22 +183,23 @@ def __build_to_tango_type():
ret[value] = key
return ret
+
TO_TANGO_TYPE = __build_to_tango_type()
_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,
+ 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,
}
# add derived scalar types to scalar to array map
@@ -207,7 +207,6 @@ for k, v in TO_TANGO_TYPE.items():
if v in _scalar_to_array_type:
_scalar_to_array_type[k] = _scalar_to_array_type[v]
-
__NO_STR_VALUE = AlrmValueNotSpec, StatusNotSet
__device_classes = None
@@ -350,7 +349,6 @@ try:
except NameError:
__str_klasses = str,
-
__int_klasses = int,
__number_klasses = numbers.Number,
__seq_klasses = collections.Sequence, bytearray, StdStringVector
@@ -373,6 +371,7 @@ except NameError:
if constants.NUMPY_SUPPORT:
import numpy
+
__int_klasses = tuple(list(__int_klasses) + [numpy.integer])
__number_klasses = tuple(list(__number_klasses) + [numpy.number])
__seq_klasses = tuple(list(__seq_klasses) + [numpy.ndarray])
@@ -384,10 +383,9 @@ __seq_klasses = tuple(__seq_klasses)
def __get_tango_type(obj):
- from .device_server import DataElement
if is_non_str_seq(obj):
tg_type, tg_format = get_tango_type(obj[0])
- tg_format = AttrDataFormat(int(tg_format)+1)
+ tg_format = AttrDataFormat(int(tg_format) + 1)
return tg_type, tg_format
elif is_pure_str(obj):
r = CmdArgType.DevString
@@ -403,7 +401,6 @@ def __get_tango_type(obj):
def __get_tango_type_numpy_support(obj):
- import numpy
try:
ndim, dtype = obj.ndim, str(obj.dtype)
if ndim > 2:
@@ -518,6 +515,7 @@ def is_scalar(tg_type):
global _scalar_types
return tg_type in _scalar_types
+
is_scalar_type = is_scalar
@@ -533,6 +531,7 @@ def is_array(tg_type):
global _array_types
return tg_type in _array_types
+
is_array_type = is_array
@@ -555,6 +554,7 @@ def is_numerical(tg_type, inc_array=False):
return False
return tg_type in _array_numerical_types
+
is_numerical_type = is_numerical
@@ -577,6 +577,7 @@ def is_int(tg_type, inc_array=False):
return False
return tg_type in _array_int_types
+
is_int_type = is_int
@@ -599,6 +600,7 @@ def is_float(tg_type, inc_array=False):
return False
return tg_type in _array_float_types
+
is_float_type = is_float
@@ -621,6 +623,7 @@ def is_bool(tg_type, inc_array=False):
return False
return tg_type in _array_bool_types
+
is_bool_type = is_bool
@@ -643,10 +646,11 @@ def is_str(tg_type, inc_array=False):
return False
return tg_type in _array_str_types
+
is_str_type = is_str
-def is_bin(tg_type, inc_array=False):
+def is_binary(tg_type, inc_array=False):
"""Tells if the given tango type is binary
:param tg_type: tango type
@@ -658,10 +662,11 @@ def is_bin(tg_type, inc_array=False):
:return: True if the given tango type is binary or False otherwise
:rtype: :py:obj:`bool`
"""
- global _scalar_bin_types
- return tg_type in _scalar_bin_types
+ global _binary_types
+ return tg_type in _binary_types
-is_bin_type = is_bin
+
+is_binary_type = is_binary
def seq_2_StdStringVector(seq, vec=None):
@@ -696,7 +701,8 @@ def StdStringVector_2_seq(vec, seq=None):
:return: a python sequence filled with the same contents as seq
:rtype: sequence<str>
"""
- if seq is None: seq = []
+ if seq is None:
+ seq = []
if not isinstance(vec, StdStringVector):
raise TypeError('vec must be a tango.StdStringVector')
for e in vec:
@@ -801,11 +807,13 @@ def seq_2_DbData(seq, vec=None):
:rtype: :class:`tango.DbData`
"""
if vec is None:
- if isinstance(seq, DbData): return seq
+ if isinstance(seq, DbData):
+ return seq
vec = DbData()
if not isinstance(vec, DbData):
raise TypeError('vec must be a tango.DbData')
- for e in seq: vec.append(e)
+ for e in seq:
+ vec.append(e)
return vec
@@ -839,11 +847,10 @@ def seqStr_2_obj(seq, tg_type, tg_format=None):
def _seqStr_2_obj_from_type(seq, tg_type):
-
if is_pure_str(seq):
seq = seq,
- # Scalar cases
+ # Scalar cases
global _scalar_int_types
if tg_type in _scalar_int_types:
return int(seq[0])
@@ -986,6 +993,8 @@ def obj_2_str(obj, tg_type=None):
obj = obj[0]
return str(obj)
# sequence cases
+ if obj is None:
+ return ''
return '\n'.join([str(i) for i in obj])
@@ -1064,6 +1073,7 @@ class CaselessList(list):
Inherited methods :
__imul__, __len__, __iter__, pop, reverse, sort
"""
+
def __init__(self, inlist=[]):
list.__init__(self)
for entry in inlist:
@@ -1302,6 +1312,7 @@ class CaselessDict(dict):
def keys(self):
return CaselessList(dict.keys(self))
+
__DEFAULT_FACT_IOR_FILE = "/tmp/rdifact.ior"
__BASE_LINE = "notifd"
__END_NOTIFD_LINE = "/DEVICE/notifd:"
@@ -1385,14 +1396,14 @@ def _notifd2db_real_db(ior_string, host=None, out=sys.stdout):
"to TANGO database", file=out)
-class EventCallBack(object):
+class EventCallback(object):
"""
Useful event callback for test purposes
Usage::
>>> dev = tango.DeviceProxy(dev_name)
- >>> cb = tango.utils.EventCallBack()
+ >>> cb = tango.utils.EventCallback()
>>> id = dev.subscribe_event("state", tango.EventType.CHANGE_EVENT, cb, [])
2011-04-06 15:33:18.910474 sys/tg_test/1 STATE CHANGE [ATTR_VALID] ON
@@ -1438,7 +1449,7 @@ class EventCallBack(object):
import datetime
now = datetime.datetime.now()
try:
- date = evt.get_date().todatetime()
+ date = self._get_date(evt)
except:
date = now
try:
@@ -1461,9 +1472,9 @@ class EventCallBack(object):
value = self._get_value(evt)
except Exception as e:
value = "Unexpected exception in getting event value: %s" % str(e)
- d = { "date" : date, "reception_date" : reception_date,
- "type" : evt_type, "dev_name" : dev_name, "name" : attr_name,
- "value" : value }
+ d = {"date": date, "reception_date": reception_date,
+ "type": evt_type, "dev_name": dev_name, "name": attr_name,
+ "value": value}
print(self._msg.format(**d), file=self._fd)
def _append(self, evt):
@@ -1473,6 +1484,14 @@ class EventCallBack(object):
evts.pop(0)
evts.append(evt)
+ def _get_date(self, evt):
+ if isinstance(evt, EventData):
+ return evt.attr_value.time.todatetime()
+ elif isinstance(evt, PipeEventData):
+ return evt.pipe_value.time.todatetime()
+ else:
+ return evt.get_date().todatetime()
+
def _get_value(self, evt):
"""Internal usage only"""
if evt.err:
@@ -1487,6 +1506,11 @@ class EventCallBack(object):
return "label='%s'; unit='%s'" % (cfg.label, cfg.unit)
elif isinstance(evt, DataReadyEventData):
return ""
+ elif isinstance(evt, PipeEventData):
+ return evt.pipe_value
+ elif isinstance(evt, DevIntrChangeEventData):
+ print("utils::_get_value()")
+ return
def get_home():
@@ -1568,7 +1592,7 @@ def from_version_str_to_hex_str(version_str):
def from_version_str_to_int(version_str):
- return int(from_version_str_to_hex_str(version_str, 16))
+ return int(from_version_str_to_hex_str(version_str), 16)
def info():