diff --git a/tangostationcontrol/tangostationcontrol/toolkit/archiver.py b/tangostationcontrol/tangostationcontrol/toolkit/archiver.py index 8f3e7a25046764eeedaf9fa2380b2fdbe76b0b6b..d6aada7d5c051b7140537dede572337f70dbbc14 100644 --- a/tangostationcontrol/tangostationcontrol/toolkit/archiver.py +++ b/tangostationcontrol/tangostationcontrol/toolkit/archiver.py @@ -7,6 +7,7 @@ from tango import DeviceProxy, AttributeProxy, DevState, DevFailed import time import json import pkg_resources +from functools import wraps logger = logging.getLogger() @@ -23,6 +24,19 @@ def attribute_name_from_url(attribute_name:str): return attribute_name +def attribute_name_url(attribute_name:str, tango_host:str = 'databaseds:10000'): + """ + For some operations Tango devices must be transformed from the form 'domain/family/name/attribute' + to 'tango://db:port/domain/family/name/attribute' + """ + if attribute_name.startswith('tango://'): + return attribute_name + + if len(attribute_name.split('/')) != 4: + raise ValueError(f"Expected attribute name of format 'domain/family/name/attribute', got {attribute_name}") + + return f"tango://{tango_host}/{attribute_name}" + def device_name_url(device_name:str, tango_host:str = 'databaseds:10000'): """ For some operations Tango devices must be transformed from the form 'domain/family/name' @@ -64,9 +78,9 @@ def warn_if_attribute_not_found(): """ def inner(func): @wraps(func) - def warn_wrapper(self, *args, **kwargs): + def warn_wrapper(self, attribute_name, *args, **kwargs): try: - return func(self, *args, **kwargs) + return func(self, attribute_name, *args, **kwargs) except DevFailed as e: if e.args[0].reason == 'Attribute not found': logger.warning(f"Attribute {attribute_name} not found!") @@ -245,15 +259,14 @@ class Archiver(): for a in attrs_list: attr_fullname = f"{device_name}/{a}".lower() attr_proxy = AttributeProxy(attr_fullname) - if attr_proxy.is_polled() is True: # if not polled attribute is also not archived + if attr_proxy.is_polled() and not self.is_attribute_archived(attr_fullname): # if not polled attribute is also not archived try: es = DeviceProxy(es_name or self.get_next_subscriber()) # choose an e.s. or get the first one available - if es.AttributeList is None or not(self.cm.AttributeSearch(a)): - polling_period = attr_proxy.get_poll_period() or self.dev_polling_time - archive_period = global_archive_period or int(attr_proxy.get_property('archive_period')['archive_period'][0]) or self.dev_archive_time - self.add_attribute_to_archiver(attr_fullname,polling_period=polling_period, - event_period=archive_period, es_name = es.name()) - #time.sleep(0.5) + polling_period = attr_proxy.get_poll_period() or self.dev_polling_time + archive_period = global_archive_period or int(attr_proxy.get_property('archive_period')['archive_period'][0]) or self.dev_archive_time + self.add_attribute_to_archiver(attr_fullname,polling_period=polling_period, + event_period=archive_period, es_name = es.name()) + #time.sleep(0.5) except IndexError as e: logger.warning(f"Attribute {attr_fullname} will not be archived because archive event period is not defined!") except Exception as e: @@ -284,7 +297,8 @@ class Archiver(): for a in attrs_list: try: attr_fullname = f"{device_name}/{a}".lower() - self.remove_attribute_from_archiver(attr_fullname) + if self.is_attribute_archived(attr_fullname): + self.remove_attribute_from_archiver(attr_fullname) except Exception as e: raise Exception from e @@ -331,16 +345,10 @@ class Archiver(): """ attribute_name = attribute_name_from_url(attribute_name) attributes = self.cm.AttributeSearch(attribute_name.lower()) - if len(attributes)>1: - # Handle case same attribute_name r/rw - if len(attributes)==2 and (attributes[0].endswith(attributes[1]+'w') or attributes[1].endswith(attributes[0]+'w')): - return True - else: - raise Exception(f"Multiple Attributes Matched: {attributes}") - elif len(attributes)==1: - return True - else: - return False + + # search returns all matches in which attribute_name is part of the name, + # so check whether an exact match is included. + return attribute_name_url(attribute_name) in attributes def update_archiving_attribute(self, attribute_name: str, polling_period: int, event_period: int, strategy: str = 'RUN'): """