From 1b7bb0e39eec829efd8d100bd881501246b61303 Mon Sep 17 00:00:00 2001 From: softir Date: Wed, 1 Apr 2020 15:02:05 +0200 Subject: [PATCH 01/17] AT5-370: Created repository structure. First release of the sub-element master device. --- cspse/__init__.py | 0 cspse/lmc/__init__.py | 0 cspse/lmc/release.py | 20 + cspse/lmc/subelement_master.py | 647 +++++++++++++++++++++ pogo/CspSubElementMaster.xmi | 433 ++++++++++++++ setup.cfg | 2 +- setup.py | 39 +- ska_python_skeleton/__init__.py | 9 - ska_python_skeleton/ska_python_skeleton.py | 22 - 9 files changed, 1122 insertions(+), 50 deletions(-) create mode 100644 cspse/__init__.py create mode 100644 cspse/lmc/__init__.py create mode 100755 cspse/lmc/release.py create mode 100644 cspse/lmc/subelement_master.py create mode 100644 pogo/CspSubElementMaster.xmi delete mode 100644 ska_python_skeleton/__init__.py delete mode 100644 ska_python_skeleton/ska_python_skeleton.py diff --git a/cspse/__init__.py b/cspse/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cspse/lmc/__init__.py b/cspse/lmc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cspse/lmc/release.py b/cspse/lmc/release.py new file mode 100755 index 0000000..4e495d0 --- /dev/null +++ b/cspse/lmc/release.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the CentralNode project +# +# +# +# Distributed under the terms of the BSD-3-Clause license. +# See LICENSE.txt for more info. + +"""Release information for Python Package""" + +name = """csp-lmc-subelement""" +version = "0.1.0" +version_info = version.split(".") +description = """SKA CSP Sub-element LMC""" +author = "INAF-OAA" +author_email = "elisabetta.giani@inaf.it" +license = """BSD-3-Clause""" +url = """https://gitlab.com/ska-telescope/csp-lmc.git""" +copyright = """INAF, SKA Telescope""" diff --git a/cspse/lmc/subelement_master.py b/cspse/lmc/subelement_master.py new file mode 100644 index 0000000..9cabff7 --- /dev/null +++ b/cspse/lmc/subelement_master.py @@ -0,0 +1,647 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the CspSubElementMaster project +# +# INAF-SKA Telescope +# +# Distributed under the terms of the GPL license. +# See LICENSE.txt for more info. + +""" CSP.LMC Sub-element Master + +A base class for the Master of a SKA Sub-element. +""" + +# PyTango imports +import tango +from tango import DebugIt +from tango.server import run +from tango.server import Device +from tango.server import attribute, command +from tango.server import device_property +from tango import AttrQuality, DispLevel, DevState +from tango import AttrWriteType, PipeWriteType +from collections import defaultdict +# Additional import +# PROTECTED REGION ID(CspSubElementMaster.additionnal_import) ENABLED START # +from ska.base.SKAMaster import SKAMaster +from ska.base.control_model import HealthState, AdminMode, LoggingLevel +from csp_lmc_common.cspcommons.utils import CmdExecState +# PROTECTED REGION END # // CspSubElementMaster.additionnal_import + +__all__ = ["CspSubElementMaster", "main"] + + +class CspSubElementMaster(SKAMaster): + """ + A base class for the Master of a SKA Sub-element. + + **Properties:** + + - Device Property + """ + # PROTECTED REGION ID(CspSubElementMaster.class_variable) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.class_variable + + # ----------------- + # Device Properties + # ----------------- + + # ---------- + # Attributes + # ---------- + + numOfDevCompletedTask = attribute( + dtype='DevUShort', + label="Number of devices that completed the task", + doc="Number of devices that completed the task", + ) + + onCmdFailure = attribute( + dtype='DevBoolean', + label="CBF command failure flag", + polling_period=1000, + doc="Failure flag set when the On command fails with error(s).", + ) + + onFailureMessage = attribute( + dtype='DevString', + label="On execution failure message", + doc="Failure message when the On command fails with error(s).", + ) + + offCmdFailure = attribute( + dtype='DevBoolean', + label="Off execution failure flag", + polling_period=1000, + doc="Failure flag set when the Off command fails with error(s).", + ) + + offFailureMessage = attribute( + dtype='DevString', + label="Off execution failure message", + doc="Failure message when the Off command fails with error(s).", + ) + + standbyCmdFailure = attribute( + dtype='DevBoolean', + label="Standby execution failure message", + polling_period=1000, + doc="Failure flag set when the Standby command fails with error(s).", + ) + + standbyFailureMessage = attribute( + dtype='DevString', + label="Standby execution failure message", + doc="Failure message when the Standby command fails with error(s).", + ) + + adminMode = attribute( + dtype=AdminMode, + access=AttrWriteType.READ_WRITE, + polling_period=1000, + memorized=True, + doc="The admin mode reported for this device. It may interpret the current device condition \nand condition of all managed devices to set this. Most possibly an aggregate attribute.", + ) + + onCommandProgress = attribute( + dtype='DevUShort', + label="Progress percentage for the On command", + polling_period=3000, + abs_change=10, + max_value=100, + min_value=0, + doc="Percentage progress implemented for commands that result in state/mode transitions for a large \nnumber of components and/or are executed in stages (e.g power up, power down)", + ) + + offCommandProgress = attribute( + dtype='DevUShort', + label="Progress percentage for the Off command", + polling_period=3000, + abs_change=10, + max_value=100, + min_value=0, + doc="Percentage progress implemented for commands that result in state/mode transitions for a large \nnumber of components and/or are executed in stages (e.g power up, power down)", + ) + + standbyCommandProgress = attribute( + dtype='DevUShort', + label="Progress percentage for the Standby command", + polling_period=3000, + abs_change=10, + max_value=100, + min_value=0, + doc="Percentage progress implemented for commands that result in state/mode transitions for a large \nnumber of components and/or are executed in stages (e.g power up, power down)", + ) + + onCmdDurationExpected = attribute( + dtype='DevUShort', + access=AttrWriteType.READ_WRITE, + label="Expected duration (sec) of the On command execution", + abs_change=0, + max_value=100, + min_value=0, + memorized=True, + doc="Set/Report the duration expected for the On command execution", + ) + + offCmdDurationExpected = attribute( + dtype='DevUShort', + access=AttrWriteType.READ_WRITE, + label="Expected duration (sec) of the Off command", + abs_change=0, + max_value=100, + min_value=0, + memorized=True, + doc="Set/Report the duration expected for the Off command execution", + ) + + standbyCmdDurationExpected = attribute( + dtype='DevUShort', + access=AttrWriteType.READ_WRITE, + label="Expected duration (sec) of the Standby command", + abs_change=0, + max_value=100, + min_value=0, + memorized=True, + doc="Set/Report the duration expected for the Standby command", + ) + + onCmdDurationMeasured = attribute( + dtype='DevUShort', + label="Measured duration (sec) of the On command execution", + abs_change=0, + max_value=100, + min_value=0, + doc="Report the measured duration of the On command execution", + ) + + offCmdDurationMeasured = attribute( + dtype='DevUShort', + label="Measured duration (sec) of the Off command", + abs_change=0, + max_value=100, + min_value=0, + doc="Report the measured duration of the Off command execution", + ) + + standbyCmdDurationMeasured = attribute( + dtype='DevUShort', + label="Measured duration (sec) of the Standby command", + abs_change=0, + max_value=100, + min_value=0, + doc="Report the measured duration of the Standby command", + ) + + onCmdTimeoutExpired = attribute( + dtype='DevBoolean', + label="On execution timeout flag", + polling_period=2000, + abs_change=1, + doc="Signal the occurence of a timeout during the execution of the on command.", + ) + + offCmdTimeoutExpired = attribute( + dtype='DevBoolean', + label="Off execution timeout flag", + polling_period=2000, + abs_change=1, + doc="Signal the occurence of a timeout during the execution of the Off command.", + ) + + standbyCmdTimeoutExpired = attribute( + dtype='DevBoolean', + label="Standby execution timeout flag.", + polling_period=2000, + abs_change=1, + doc="Signal the occurence of a timeout during the execution of the Standby command.", + ) + + listOfDevCompletedTask = attribute( + dtype=('DevString',), + max_dim_x=100, + label="List of devices that completed the task", + doc="List of devices that completed the task", + ) + + listOfComponents = attribute( + dtype=('DevString',), + max_dim_x=100, + label="List of sub-element components", + doc="The list o the FQDNs of the sub-element components.", + ) + + # --------------- + # General methods + # --------------- + + def init_device(self): + """Initialises the attributes and properties of the CspSubElementMaster.""" + SKAMaster.init_device(self) + # PROTECTED REGION ID(CspSubElementMaster.init_device) ENABLED START # + # PROTECTED REGION ID(CspSubElementMaster.init_device) ENABLED START # + # _cmd_execution_state: implement the execution state of a long-running + # command for the whole CSP. Setting this attribute prevent the execution + # of the same command while it is already running. + # implemented as a default dictionary: + # keys: command name + # values:command state + self._cmd_execution_state = defaultdict(lambda: CmdExecState.IDLE) + # _cmd_progress: report the execution progress of a long-running command + # implemented as a dictionary: + # keys: command name ('on', 'off'..) + # values: the percentage + self._cmd_progress = defaultdict(lambda: 0) + + # _cmd_duration_expected: store the duration (in sec.) configured for + # a long-running command + # Implemented asdefault dictionary + # keys: command name ('on', 'off',..) + # values: the duration (in sec) + self._cmd_duration_expected = defaultdict(lambda: 30) + + # _cmd_duration_measured: report the measured duration (in sec.) for + # a long-running command + # Implemented as default dictionary + # keys: command name ('on', 'off',..) + # values: the duration (in sec) + self._cmd_duration_measured = defaultdict(lambda: 0) + + # _timeout_expired: report the timeout flag + # Implemented as a dictionary + # keys: command name ('on', 'off', 'standby'..) + # values: True/False + self._timeout_expired = defaultdict(lambda: False) + + # _failure_raised: report the failure flag + # Implemented as a dictionary + # keys: command name ('on', 'off', 'standby'..) + # values: True/False + self._failure_raised = defaultdict(lambda: False) + + # _failure_message: report the failure message + # Implemented as a dictionary + # keys: command name ('on', 'off', 'standby'..) + # values: the message + self._failure_message = defaultdict(lambda: '') + + # _list_dev_completed_task: for each long-running command report the list + # of subordinate sub-element components that completed the task + # Implemented as a dictionary + # keys: the command name ('on', 'off',...) + # values: the list of components + self._list_dev_completed_task = defaultdict(lambda: []) + + # _list_of_components: report the list of subordinate + # sub-element components. + # Implemented as a dictionary + # keys: the command name ('on', 'off',...) + # values: the list of components + self._list_of_components = defaultdict(lambda: []) + + # _num_dev_completed_task: for each long-running command report the number + # of subordinate components that completed the task + # Implemented as a dictionary + # keys: the command name ('on', 'off',...) + # values: the number of components + self._num_dev_completed_task = defaultdict(lambda:0) + + # the last executed command + self._last_executed_command = "" + + # PROTECTED REGION END # // CspSubElementMaster.init_device + + def always_executed_hook(self): + """Method always executed before any TANGO command is executed.""" + # PROTECTED REGION ID(CspSubElementMaster.always_executed_hook) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.always_executed_hook + + def delete_device(self): + """Hook to delete resources allocated in init_device. + + This method allows for any memory or other resources allocated in the + init_device method to be released. This method is called by the device + destructor and by the device Init command. + """ + # PROTECTED REGION ID(CspSubElementMaster.delete_device) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.delete_device + # ------------------ + # Attributes methods + # ------------------ + + def read_numOfDevCompletedTask(self): + # PROTECTED REGION ID(CspSubElementMaster.numOfDevCompletedTask_read) ENABLED START # + """Return the numOfDevCompletedTask attribute.""" + return self._num_dev_completed_task + # PROTECTED REGION END # // CspSubElementMaster.numOfDevCompletedTask_read + + def read_onCmdFailure(self): + # PROTECTED REGION ID(CspSubElementMaster.onCmdFailure_read) ENABLED START # + """Return the onCmdFailure attribute.""" + return self._failure_raised['on'] + # PROTECTED REGION END # // CspSubElementMaster.onCmdFailure_read + + def read_onFailureMessage(self): + # PROTECTED REGION ID(CspSubElementMaster.onFailureMessage_read) ENABLED START # + """Return the onFailureMessage attribute.""" + return self._failure_message['on'] + # PROTECTED REGION END # // CspSubElementMaster.onFailureMessage_read + + def read_offCmdFailure(self): + # PROTECTED REGION ID(CspSubElementMaster.offCmdFailure_read) ENABLED START # + """Return the offCmdFailure attribute.""" + return self._failure_raised['off'] + # PROTECTED REGION END # // CspSubElementMaster.offCmdFailure_read + + def read_offFailureMessage(self): + # PROTECTED REGION ID(CspSubElementMaster.offFailureMessage_read) ENABLED START # + """Return the offFailureMessage attribute.""" + return self._failure_message['off'] + # PROTECTED REGION END # // CspSubElementMaster.offFailureMessage_read + + def read_standbyCmdFailure(self): + # PROTECTED REGION ID(CspSubElementMaster.standbyCmdFailure_read) ENABLED START # + """Return the standbyCmdFailure attribute.""" + return self._failure_message['standby'] + # PROTECTED REGION END # // CspSubElementMaster.standbyCmdFailure_read + + def read_standbyFailureMessage(self): + # PROTECTED REGION ID(CspSubElementMaster.standbyFailureMessage_read) ENABLED START # + """Return the standbyFailureMessage attribute.""" + return self._failure_message['standby'] + # PROTECTED REGION END # // CspSubElementMaster.standbyFailureMessage_read + + def read_adminMode(self): + # PROTECTED REGION ID(CspSubElementMaster.adminMode_read) ENABLED START # + """Return the adminMode attribute.""" + return self._admin_mode + # PROTECTED REGION END # // CspSubElementMaster.adminMode_read + + def write_adminMode(self, value): + # PROTECTED REGION ID(CspSubElementMaster.adminMode_write) ENABLED START # + """Set the adminMode attribute.""" + self._admin_mode = value + # PROTECTED REGION END # // CspSubElementMaster.adminMode_write + + def read_onCommandProgress(self): + # PROTECTED REGION ID(CspSubElementMaster.onCommandProgress_read) ENABLED START # + """Return the onCommandProgress attribute.""" + return self._cmd_progress['on'] + # PROTECTED REGION END # // CspSubElementMaster.onCommandProgress_read + + def read_offCommandProgress(self): + # PROTECTED REGION ID(CspSubElementMaster.offCommandProgress_read) ENABLED START # + """Return the offCommandProgress attribute.""" + return self._cmd_progress['off'] + # PROTECTED REGION END # // CspSubElementMaster.offCommandProgress_read + + def read_standbyCommandProgress(self): + # PROTECTED REGION ID(CspSubElementMaster.standbyCommandProgress_read) ENABLED START # + """Return the standbyCommandProgress attribute.""" + return self._cmd_progress['standby'] + # PROTECTED REGION END # // CspSubElementMaster.standbyCommandProgress_read + + def read_onCmdDurationExpected(self): + # PROTECTED REGION ID(CspSubElementMaster.onCmdDurationExpected_read) ENABLED START # + """Return the onCmdDurationExpected attribute.""" + return self._cmd_duration_expected['on'] + # PROTECTED REGION END # // CspSubElementMaster.onCmdDurationExpected_read + + def write_onCmdDurationExpected(self, value): + # PROTECTED REGION ID(CspSubElementMaster.onCmdDurationExpected_write) ENABLED START # + """Set the onCmdDurationExpected attribute.""" + self._cmd_duration_expected['on'] = value + # PROTECTED REGION END # // CspSubElementMaster.onCmdDurationExpected_write + + def read_offCmdDurationExpected(self): + # PROTECTED REGION ID(CspSubElementMaster.offCmdDurationExpected_read) ENABLED START # + """Return the offCmdDurationExpected attribute.""" + return self._cmd_duration_expected['off'] + # PROTECTED REGION END # // CspSubElementMaster.offCmdDurationExpected_read + + def write_offCmdDurationExpected(self, value): + # PROTECTED REGION ID(CspSubElementMaster.offCmdDurationExpected_write) ENABLED START # + """Set the offCmdDurationExpected attribute.""" + self._cmd_duration_expected['off'] = value + # PROTECTED REGION END # // CspSubElementMaster.offCmdDurationExpected_write + + def read_standbyCmdDurationExpected(self): + # PROTECTED REGION ID(CspSubElementMaster.standbyCmdDurationExpected_read) ENABLED START # + """Return the standbyCmdDurationExpected attribute.""" + return self._cmd_duration_expected['standby'] + # PROTECTED REGION END # // CspSubElementMaster.standbyCmdDurationExpected_read + + def write_standbyCmdDurationExpected(self, value): + # PROTECTED REGION ID(CspSubElementMaster.standbyCmdDurationExpected_write) ENABLED START # + """Set the standbyCmdDurationExpected attribute.""" + self._cmd_duration_expected['standby'] = value + # PROTECTED REGION END # // CspSubElementMaster.standbyCmdDurationExpected_write + + def read_onCmdDurationMeasured(self): + # PROTECTED REGION ID(CspSubElementMaster.onCmdDurationMeasured_read) ENABLED START # + """Return the onCmdDurationMeasured attribute.""" + return self._cmd_duration_measured['on']return self._cmd_duration_measured['on'] + # PROTECTED REGION END # // CspSubElementMaster.onCmdDurationMeasured_read + + def read_offCmdDurationMeasured(self): + # PROTECTED REGION ID(CspSubElementMaster.offCmdDurationMeasured_read) ENABLED START # + """Return the offCmdDurationMeasured attribute.""" + return self._cmd_duration_measured['off'] + # PROTECTED REGION END # // CspSubElementMaster.offCmdDurationMeasured_read + + def read_standbyCmdDurationMeasured(self): + # PROTECTED REGION ID(CspSubElementMaster.standbyCmdDurationMeasured_read) ENABLED START # + """Return the standbyCmdDurationMeasured attribute.""" + return self._cmd_duration_measured['standby'] + # PROTECTED REGION END # // CspSubElementMaster.standbyCmdDurationMeasured_read + + def read_onCmdTimeoutExpired(self): + # PROTECTED REGION ID(CspSubElementMaster.onCmdTimeoutExpired_read) ENABLED START # + """Return the onCmdTimeoutExpired attribute.""" + return self._timeout_expired['on'] + # PROTECTED REGION END # // CspSubElementMaster.onCmdTimeoutExpired_read + + def read_offCmdTimeoutExpired(self): + # PROTECTED REGION ID(CspSubElementMaster.offCmdTimeoutExpired_read) ENABLED START # + """Return the offCmdTimeoutExpired attribute.""" + return self._timeout_expired['off'] + + # PROTECTED REGION END # // CspSubElementMaster.offCmdTimeoutExpired_read + + def read_standbyCmdTimeoutExpired(self): + # PROTECTED REGION ID(CspSubElementMaster.standbyCmdTimeoutExpired_read) ENABLED START # + """Return the standbyCmdTimeoutExpired attribute.""" + return self._timeout_expired['standby'] + # PROTECTED REGION END # // CspSubElementMaster.standbyCmdTimeoutExpired_read + + def read_listOfDevCompletedTask(self): + # PROTECTED REGION ID(CspSubElementMaster.listOfDevCompletedTask_read) ENABLED START # + """Return the listOfDevCompletedTask attribute.""" + return self._list_dev_completed_task + # PROTECTED REGION END # // CspSubElementMaster.listOfDevCompletedTask_read + + def read_listOfComponents(self): + # PROTECTED REGION ID(CspSubElementMaster.listOfComponents_read) ENABLED START # + """Return the listOfComponents attribute.""" + return self._list_of_components + # PROTECTED REGION END # // CspSubElementMaster.listOfComponents_read + + # -------- + # Commands + # -------- + + @AdminModeCheck('On') + def is_On_allowed(self): + """ + *TANGO is_allowed method* + + Command *On* is allowed when the device *State* is STANDBY. + + :return: True if the method is allowed, otherwise False. + """ + # PROTECTED REGION ID(CspMaster.is_On_allowed) ENABLED START # + # Note: as per SKA Guidelines, the command is allowed when + if self.get_state() not in [tango.DevState.STANDBY, tango.DevState.ON]: + return False + return True + + @command( + dtype_in='DevVarStringArray', + doc_in="The list of sub-element components FQDNs to switch-on or an empty list to switch-on the whole " + "CSP Sub-element." + " " + "If the array length is 0, the command applies to the whole CSP Sub-Element. If the " + "array length is > 1, each array element specifies the FQDN of the" + "CSP SubElement component to switch ON.", + ) + @DebugIt() + def On(self, argin): + # PROTECTED REGION ID(CspSubElementMaster.On) ENABLED START # + """ + Switch-on the CSP sub-element components specified by the input argument. If no argument is + specified, the command is issued on all the CSP sub-element components. + The command is executed if the *AdminMode* is ONLINE or *MAINTENANCE*. + If the AdminMode is *OFFLINE*, *NOT-FITTED* or *RESERVED*, the method throws an + exception. + + :param argin: 'DevVarStringArray' + The list of sub-element components FQDNs to switch-on or an empty list to switch-on the whole + CSP Sub-element. + + If the array length is 0, the command applies to the whole CSP Sub-Element. If the + array length is > 1, each array element specifies the FQDN of the + CSP SubElement component to switch ON. + + :return:None + """ + pass + # PROTECTED REGION END # // CspSubElementMaster.On + + @AdminModeCheck('Off') + def is_Off_allowed(self): + """ + *TANGO is_allowed method* + + Command *Off* is allowed when the device *State* is STANDBY. + + :return: True if the method is allowed, otherwise False. + """ + # PROTECTED REGION ID(CspMaster.is_On_allowed) ENABLED START # + # Note: as per SKA Guidelines, the command is allowed when + if self.get_state() not in [tango.DevState.STANDBY, tango.DevState.OFF]: + return False + return True + + @command( + dtype_in='DevVarStringArray', + doc_in="If the array length is 0, the command applies to the whole" + "CSP Sub-element." + "If the array length is > 1, each array element specifies the FQDN of the" + "CSP SubElement component to switch OFF.", + ) + @DebugIt() + def Off(self, argin): + # PROTECTED REGION ID(CspSubElementMaster.Off) ENABLED START # + """ + Switch-off the CSP sub-element components specified by the input argument. + If no argument is specified, the command is issued to all the CSP + sub-element components. + + :param argin: 'DevVarStringArray' + If the array length is 0, the command applies to the whole + CSP Sub-element. + If the array length is > 1, each array element specifies the FQDN of the + CSP SubElement component to switch OFF. + + :return:None + """ + pass + # PROTECTED REGION END # // CspSubElementMaster.Off + + @AdminModeCheck('Standby') + def is_Standby_allowed(self): + """ + *TANGO is_allowed method* + + Command *Standby* is allowed when the device *State* is ON. + + :return: True if the method is allowed, otherwise False. + """ + # PROTECTED REGION ID(CspMaster.is_On_allowed) ENABLED START # + # Note: as per SKA Guidelines, the command is allowed when + if self.get_state() not in [tango.DevState.STANDBY, tango.DevState.ON]: + return False + return True + + @command( + dtype_in='DevVarStringArray', + doc_in="If the array length is 0, the command applies to the whole" + "CSP sub-element." + "If the array length is > 1, each array element specifies the FQDN of the" + "CSP SubElement icomponent to put in STANDBY mode.", + ) + @DebugIt() + def Standby(self, argin): + # PROTECTED REGION ID(CspSubElementMaster.Standby) ENABLED START # + """ + Transit the CSP Sub-element or one or more CSP SubElement components from ON/OFF to + STANDBY. + + :param argin: 'DevVarStringArray' + If the array length is 0, the command applies to the whole + CSP sub-element. + If the array length is > 1, each array element specifies the FQDN of the + CSP SubElement icomponent to put in STANDBY mode. + + :return:None + """ + pass + # PROTECTED REGION END # // CspSubElementMaster.Standby + + @command( + ) + @DebugIt() + def Upgrade(self): + # PROTECTED REGION ID(CspSubElementMaster.Upgrade) ENABLED START # + """ + + :return:None + """ + pass + # PROTECTED REGION END # // CspSubElementMaster.Upgrade + +# ---------- +# Run server +# ---------- + + +def main(args=None, **kwargs): + """Main function of the CspSubElementMaster module.""" + # PROTECTED REGION ID(CspSubElementMaster.main) ENABLED START # + return run((CspSubElementMaster,), args=args, **kwargs) + # PROTECTED REGION END # // CspSubElementMaster.main + + +if __name__ == '__main__': + main() diff --git a/pogo/CspSubElementMaster.xmi b/pogo/CspSubElementMaster.xmi new file mode 100644 index 0000000..567b8c2 --- /dev/null +++ b/pogo/CspSubElementMaster.xmi @@ -0,0 +1,433 @@ + + + + + + + + + + + + + 4 + + + + + 4 + + + + + + + + + + + + + 16 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/setup.cfg b/setup.cfg index 3f0083c..428ca67 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,7 +7,7 @@ test=pytest [coverage:run] branch = True -source = ska_python_skeleton +source = cspse [tool:pytest] testpaths = tests diff --git a/setup.py b/setup.py index 9a9bf58..0f0f99b 100644 --- a/setup.py +++ b/setup.py @@ -6,34 +6,36 @@ from setuptools import setup with open('README.md') as readme_file: readme = readme_file.read() +RELEASE_FILENAME = os.path.join(setup_dir, 'cspse','lmc','release.py') +exec(open(RELEASE_FILENAME).read(), INFO) setup( - name='ska_python_skeleton', - version='0.0.0', - description="", - long_description=readme + '\n\n', - author="Your Name", - author_email='your.email@mail.com', - url='https://github.com/ska-telescope/ska-python-skeleton', - packages=[ - 'ska_python_skeleton', - ], - package_dir={'ska_python_skeleton': - 'ska_python_skeleton'}, + name=INFO['name'] + version=INFO['version'] + description=INFO['description'], + author=INFO['author'], + author_email=INFO['author_email'], + packages=find_packages(), + license=INFO['license'], + url=INFO['url'], + long_description=long_description, + keywords="csp lmc ska tango", include_package_data=True, license="BSD license", zip_safe=False, classifiers=[ - 'Development Status :: 2 - Pre-Alpha', + 'Development Status :: 3 - Alpha', 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', + 'Operating System :: POSIX :: Linux', + 'License :: Other/Proprietary License', 'Natural Language :: English', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', ], test_suite='tests', - install_requires=[], # FIXME: add your package's dependencies to this list + install_requires=[ + 'pytango >=9.3.1', + 'future', + 'lmcbaseclasses > 0.5.0', + ], setup_requires=[ # dependency for `python setup.py test` 'pytest-runner', @@ -46,6 +48,7 @@ setup( 'pytest-cov', 'pytest-json-report', 'pycodestyle', + 'mock' ], extras_require={ 'dev': ['prospector[with_pyroma]', 'yapf', 'isort'], diff --git a/ska_python_skeleton/__init__.py b/ska_python_skeleton/__init__.py deleted file mode 100644 index 82e49f1..0000000 --- a/ska_python_skeleton/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -# -*- coding: utf-8 -*- - -"""Module init code.""" - - -__version__ = '0.0.0' - -__author__ = 'Your Name' -__email__ = 'your.email@mail.com' diff --git a/ska_python_skeleton/ska_python_skeleton.py b/ska_python_skeleton/ska_python_skeleton.py deleted file mode 100644 index 7dd613e..0000000 --- a/ska_python_skeleton/ska_python_skeleton.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- - -#"""Define function placeholders and test function examples.""" - - -# TODO: Replace all the following code with the desired functionality for the package -def function_example(): - """Example: function outside of a class""" - - -# TODO: Replace all the following code with the desired functionality for the package -class SKA: - """Define class, methods etc""" - - something = 0 - - def example(self): - """Example: Define non return function for subsequent test.""" - - def example_2(self): - """Example: Define function for subsequent test with specific return value.""" - return 2 -- GitLab From 5864627a7b5fbf08e5b69bea41de4da138952e9f Mon Sep 17 00:00:00 2001 From: softir Date: Thu, 2 Apr 2020 16:28:37 +0200 Subject: [PATCH 02/17] AT5-370: Added docker folder with docker and docker-compose configuration files. Updated setup.cfg and setup.py. --- docker/.make/.make-release-support | 106 +++++++++++++ docker/.make/Makefile.mk | 137 ++++++++++++++++ docker/.release | 22 +++ docker/Dockerfile | 11 ++ docker/Makefile | 197 +++++++++++++++++++++++ docker/config/csplmc_dsconfig.json | 240 +++++++++++++++++++++++++++++ docker/se-lmc.yml | 67 ++++++++ docker/se-tangodb.yml | 50 ++++++ docker/test-harness/Makefile | 31 ++++ docker/test-harness/README.md | 3 + setup.cfg | 10 +- setup.py | 25 ++- 12 files changed, 892 insertions(+), 7 deletions(-) create mode 100644 docker/.make/.make-release-support create mode 100644 docker/.make/Makefile.mk create mode 100644 docker/.release create mode 100644 docker/Dockerfile create mode 100644 docker/Makefile create mode 100644 docker/config/csplmc_dsconfig.json create mode 100644 docker/se-lmc.yml create mode 100644 docker/se-tangodb.yml create mode 100644 docker/test-harness/Makefile create mode 100644 docker/test-harness/README.md diff --git a/docker/.make/.make-release-support b/docker/.make/.make-release-support new file mode 100644 index 0000000..f1f3a2c --- /dev/null +++ b/docker/.make/.make-release-support @@ -0,0 +1,106 @@ +#!/bin/bash +# +# Copyright 2015 Xebia Nederland B.V. +# Modifications copyright 2019 SKA Organisation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +function hasChanges() { + test -n "$(git status -s .)" +} + +function getRelease() { + awk -F= '/^release=/{print $2}' .release +} + +function getBaseTag() { + sed -n -e "s/^tag=\(.*\)$(getRelease)\$/\1/p" .release +} + +function getTag() { + if [ -z "$1" ] ; then + awk -F= '/^tag/{print $2}' .release + else + echo "$(getBaseTag)$1" + fi +} + +function setRelease() { + if [ -n "$1" ] ; then + sed -i.x -e "s/^tag=.*/tag=$(getTag $1)/" .release + sed -i.x -e "s/^release=.*/release=$1/g" .release + rm -f .release.x + runPreTagCommand "$1" + else + echo "ERROR: missing release version parameter " >&2 + return 1 + fi +} + +function runPreTagCommand() { + if [ -n "$1" ] ; then + COMMAND=$(sed -n -e "s/@@RELEASE@@/$1/g" -e 's/^pre_tag_command=\(.*\)/\1/p' .release) + if [ -n "$COMMAND" ] ; then + if ! OUTPUT=$(bash -c "$COMMAND" 2>&1) ; then echo $OUTPUT >&2 && exit 1 ; fi + fi + else + echo "ERROR: missing release version parameter " >&2 + return 1 + fi +} + +function tagExists() { + tag=${1:-$(getTag)} + test -n "$tag" && test -n "$(git tag | grep "^$tag\$")" +} + +function differsFromRelease() { + tag=$(getTag) + ! tagExists $tag || test -n "$(git diff --shortstat -r $tag .)" +} + +function getVersion() { + result=$(getRelease) + + if differsFromRelease; then + result="$result-$(git log -n 1 --format=%h .)" + fi + + if hasChanges ; then + result="$result-dirty" + fi + echo $result +} + +function nextPatchLevel() { + version=${1:-$(getRelease)} + major_and_minor=$(echo $version | cut -d. -f1,2) + patch=$(echo $version | cut -d. -f3) + version=$(printf "%s.%d" $major_and_minor $(($patch + 1))) + echo $version +} + +function nextMinorLevel() { + version=${1:-$(getRelease)} + major=$(echo $version | cut -d. -f1); + minor=$(echo $version | cut -d. -f2); + version=$(printf "%d.%d.0" $major $(($minor + 1))) ; + echo $version +} + +function nextMajorLevel() { + version=${1:-$(getRelease)} + major=$(echo $version | cut -d. -f1); + version=$(printf "%d.0.0" $(($major + 1))) + echo $version +} diff --git a/docker/.make/Makefile.mk b/docker/.make/Makefile.mk new file mode 100644 index 0000000..c819659 --- /dev/null +++ b/docker/.make/Makefile.mk @@ -0,0 +1,137 @@ +# +# Copyright 2015 Xebia Nederland B.V. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +ifeq ($(strip $(PROJECT)),) + NAME=$(shell basename $(CURDIR)) +else + NAME=$(PROJECT) +endif + +RELEASE_SUPPORT := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))/.make-release-support + +ifeq ($(strip $(DOCKER_REGISTRY_HOST)),) + DOCKER_REGISTRY_HOST = nexus.engageska-portugal.pt +endif + +ifeq ($(strip $(DOCKER_REGISTRY_USER)),) + DOCKER_REGISTRY_USER = ska-docker +endif + +IMAGE=$(DOCKER_REGISTRY_HOST)/$(DOCKER_REGISTRY_USER)/$(NAME) + +#VERSION = release version + git sha +VERSION=$(shell . $(RELEASE_SUPPORT) ; getVersion) + +#BASE_VERSION +BASE_VERSION=$(shell . $(RELEASE_SUPPORT) ; getRelease) + +#TAG = project name + release version +TAG=$(shell . $(RELEASE_SUPPORT); getTag) + +#DEFAULT_TAG = image name + BASE_VERSION +DEFAULT_TAG=$(IMAGE):$(BASE_VERSION) + + +SHELL=/bin/bash + +DOCKER_BUILD_CONTEXT=.. +DOCKER_FILE_PATH=Dockerfile + +.PHONY: pre-build docker-build post-build build release patch-release minor-release major-release tag check-status check-release showver \ + push pre-push do-push post-push + +build: pre-build docker-build post-build ## build the application image + +pre-build: + +post-build: + +pre-push: + +post-push: + +docker-build: .release + @echo "Building image: $(IMAGE):$(VERSION)" + @echo "NAME: $(NAME)" + docker build $(DOCKER_BUILD_ARGS) -t $(IMAGE):$(VERSION) $(DOCKER_BUILD_CONTEXT) -f $(DOCKER_FILE_PATH) --build-arg DOCKER_REGISTRY_HOST=$(DOCKER_REGISTRY_HOST) --build-arg DOCKER_REGISTRY_USER=$(DOCKER_REGISTRY_USER) + @DOCKER_MAJOR=$(shell docker -v | sed -e 's/.*version //' -e 's/,.*//' | cut -d\. -f1) ; \ + DOCKER_MINOR=$(shell docker -v | sed -e 's/.*version //' -e 's/,.*//' | cut -d\. -f2) ; \ + if [ $$DOCKER_MAJOR -eq 1 ] && [ $$DOCKER_MINOR -lt 10 ] ; then \ + echo docker tag -f $(IMAGE):$(VERSION) $(IMAGE):latest ;\ + docker tag -f $(IMAGE):$(VERSION) $(IMAGE):latest ;\ + else \ + echo docker tag $(IMAGE):$(VERSION) $(IMAGE):latest ;\ + docker tag $(IMAGE):$(VERSION) $(IMAGE):latest ; \ + fi + +release: check-status check-release build push + +push: pre-push do-push post-push ## push the image to the Docker registry + +do-push: ## Push the image tagged as $(IMAGE):$(VERSION) and $(DEFAULT_TAG) + @echo -e "Tagging: $(IMAGE):$(VERSION) -> $(DEFAULT_TAG)" + docker tag $(IMAGE):$(VERSION) $(DEFAULT_TAG) + @echo -e "Pushing: $(IMAGE):$(VERSION)" + docker push $(IMAGE):$(VERSION) + @echo -e "Pushing: $(DEFAULT_TAG)" + docker push $(DEFAULT_TAG) + +tag_latest: do-push ## Tag the images as latest + @echo "Tagging: $(DEFAULT_TAG) -> $(IMAGE):latest" + @docker tag $(DEFAULT_TAG) $(IMAGE):latest + +push_latest: tag_latest ## Push the image tagged as :latest + @echo "Pushing: $(IMAGE):latest" + @docker push $(IMAGE):latest + +snapshot: build push + +showver: .release + @. $(RELEASE_SUPPORT); getVersion + +bump-patch-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextPatchLevel) +bump-patch-release: .release tag + +bump-minor-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextMinorLevel) +bump-minor-release: .release tag + +bump-major-release: VERSION := $(shell . $(RELEASE_SUPPORT); nextMajorLevel) +bump-major-release: .release tag + +patch-release: tag-patch-release release + @echo $(VERSION) + +minor-release: tag-minor-release release + @echo $(VERSION) + +major-release: tag-major-release release + @echo $(VERSION) + +tag: TAG=$(shell . $(RELEASE_SUPPORT); getTag $(VERSION)) +tag: check-status +# @. $(RELEASE_SUPPORT) ; ! tagExists $(TAG) || (echo "ERROR: tag $(TAG) for version $(VERSION) already tagged in git" >&2 && exit 1) ; + @. $(RELEASE_SUPPORT) ; setRelease $(VERSION) +# git add . +# git commit -m "bumped to version $(VERSION)" ; +# git tag $(TAG) ; +# @ if [ -n "$(shell git remote -v)" ] ; then git push --tags ; else echo 'no remote to push tags to' ; fi + +check-status: + @. $(RELEASE_SUPPORT) ; ! hasChanges || (echo "ERROR: there are still outstanding changes" >&2 && exit 1) ; + +check-release: .release + @. $(RELEASE_SUPPORT) ; tagExists $(TAG) || (echo "ERROR: version not yet tagged in git. make [minor,major,patch]-release." >&2 && exit 1) ; + @. $(RELEASE_SUPPORT) ; ! differsFromRelease $(TAG) || (echo "ERROR: current directory differs from tagged $(TAG). make [minor,major,patch]-release." ; exit 1) diff --git a/docker/.release b/docker/.release new file mode 100644 index 0000000..87dca79 --- /dev/null +++ b/docker/.release @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the CSP.LMC prototype project +# +# +# Distributed under the terms of the BSD-3-Clause license. +# See LICENSE.txt for more info. + +"""Release information for Python Package""" + +name = """csplmc-subelement""" +version = "0.1.0" +version_info = version.split(".") +description = """SKA CSP.LMC Subelement Classes""" +author = "E.G" +author_email = "elisabetta.giani@inaf.it" +license = """BSD-3-Clause""" +url = """www.tango-controls.org""" +copyright = """""" + +release=0.1.0 +tag=csp-lmc-subelement-0.1.0 diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..11f7566 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,11 @@ +FROM nexus.engageska-portugal.pt/ska-docker/ska-python-buildenv:9.3.1 AS buildenv +FROM nexus.engageska-portugal.pt/ska-docker/ska-python-runtime:9.3.1 AS runtime + +# create ipython profile to so that itango doesn't fail if ipython hasn't run yet +RUN ipython profile create +#RUN python3 -m pip install --user pytest-forked +ENV PATH=/home/tango/.local/bin:$PATH +#install csp-lmc-common with dependencies +RUN python3 -m pip install -e . --user --extra-index-url https://nexus.engageska-portugal.pt/repository/pypi/simple + +CMD ["/venv/bin/python", "/app/cspse/lmc/SubElementMaster.py" ] diff --git a/docker/Makefile b/docker/Makefile new file mode 100644 index 0000000..540912c --- /dev/null +++ b/docker/Makefile @@ -0,0 +1,197 @@ +# +# Project makefile for a Tango project. You should normally only need to modify +# DOCKER_REGISTRY_USER and PROJECT below. +# + +# +# DOCKER_REGISTRY_HOST, DOCKER_REGISTRY_USER and PROJECT are combined to define +# the Docker tag for this project. The definition below inherits the standard +# value for DOCKER_REGISTRY_HOST (=rnexus.engageska-portugal.pt) and overwrites +# DOCKER_REGISTRY_USER and PROJECT to give a final Docker tag of +# nexus.engageska-portugal.pt/tango-example/csplmc +# + +DOCKER_REGISTRY_USER:=ska-docker +PROJECT = csp-lmc-subelement + +# +# include makefile to pick up the standard Make targets, e.g., 'make build' +# build, 'make push' docker push procedure, etc. The other Make targets +# ('make interactive', 'make test', etc.) are defined in this file. +# +include .make/Makefile.mk + +# +# IMAGE_TO_TEST defines the tag of the Docker image to test +# +IMAGE_TO_TEST = $(DOCKER_REGISTRY_HOST)/$(DOCKER_REGISTRY_USER)/$(PROJECT):latest + +# +# CACHE_VOLUME is the name of the Docker volume used to cache eggs and wheels +# used during the test procedure. The volume is not used during the build +# procedure +# +CACHE_VOLUME = $(PROJECT)-test-cache + +# optional docker run-time arguments +DOCKER_RUN_ARGS = + +# +# Never use the network=host mode when running CI jobs, and add extra +# distinguishing identifiers to the network name and container names to +# prevent collisions with jobs from the same project running at the same +# time. +# +ifneq ($(CI_JOB_ID),) +NETWORK_MODE := tangonet-$(CI_JOB_ID) +CONTAINER_NAME_PREFIX := $(PROJECT)-$(CI_JOB_ID)- +else +CONTAINER_NAME_PREFIX := $(PROJECT)- +endif + +COMPOSE_FILES := $(wildcard *.yml) +COMPOSE_FILE_ARGS := $(foreach yml,$(COMPOSE_FILES),-f $(yml)) + +ifeq ($(OS),Windows_NT) + $(error Sorry, Windows is not supported yet) +else + UNAME_S := $(shell uname -s) + ifeq ($(UNAME_S),Linux) + DISPLAY ?= :0.0 + NETWORK_MODE ?= host + XAUTHORITY_MOUNT := /tmp/.X11-unix:/tmp/.X11-unix + XAUTHORITY ?= /hosthome/.Xauthority + # /bin/sh (=dash) does not evaluate 'docker network' conditionals correctly + SHELL := /bin/bash + endif + ifeq ($(UNAME_S),Darwin) + IF_INTERFACE := $(shell netstat -nr | awk '{ if ($$1 ~/default/) { print $$6} }') + DISPLAY := $(shell ifconfig $(IF_INTERFACE) | awk '{ if ($$1 ~/inet$$/) { print $$2} }'):0 + # network_mode = host doesn't work on MacOS, so fix to the internal network + NETWORK_MODE := tangonet + XAUTHORITY_MOUNT := $(HOME):/hosthome:ro + XAUTHORITY := /hosthome/.Xauthority + endif +endif + +# +# When running in network=host mode, point devices at a port on the host +# machine rather than at the container. +# +ifeq ($(NETWORK_MODE),host) +TANGO_HOST := $(shell hostname):10000 +MYSQL_HOST := $(shell hostname):3306 +else +# distinguish the bridge network from others by adding the project name +NETWORK_MODE := $(NETWORK_MODE)-$(PROJECT) +TANGO_HOST := $(CONTAINER_NAME_PREFIX)databaseds:10000 +MYSQL_HOST := $(CONTAINER_NAME_PREFIX)tangodb:3306 +endif + + +DOCKER_COMPOSE_ARGS := DISPLAY=$(DISPLAY) XAUTHORITY=$(XAUTHORITY) TANGO_HOST=$(TANGO_HOST) \ + NETWORK_MODE=$(NETWORK_MODE) XAUTHORITY_MOUNT=$(XAUTHORITY_MOUNT) MYSQL_HOST=$(MYSQL_HOST) \ + DOCKER_REGISTRY_HOST=$(DOCKER_REGISTRY_HOST) DOCKER_REGISTRY_USER=$(DOCKER_REGISTRY_USER) \ + CONTAINER_NAME_PREFIX=$(CONTAINER_NAME_PREFIX) COMPOSE_IGNORE_ORPHANS=true + +# +# Defines a default make target so that help is printed if make is called +# without a target +# +.DEFAULT_GOAL := help + +# +# defines a function to copy the ./test-harness directory into the container +# and then runs the requested make target in the container. The container is: +# +# 1. attached to the network of the docker-compose test system +# 2. uses a persistent volume to cache Python eggs and wheels so that fewer +# downloads are required +# 3. uses a transient volume as a working directory, in which untarred files +# and test output can be written in the container and subsequently copied +# to the host +# +make = tar -c test-harness/ | \ + docker run -i --rm --network=$(NETWORK_MODE) \ + -e TANGO_HOST=$(TANGO_HOST) \ + -v $(CACHE_VOLUME):/home/tango/.cache \ + -v /build -w /build -u tango $(DOCKER_RUN_ARGS) $(IMAGE_TO_TEST) \ + bash -c "sudo chown -R tango:tango /build && \ + tar x --strip-components 1 --warning=all && \ + make TANGO_HOST=$(TANGO_HOST) $1" + +test: DOCKER_RUN_ARGS = --volumes-from=$(BUILD) +test: build up ## test the application + @echo "BUILD: $(BUILD)" + $(INIT_CACHE) + $(call make,test); \ + status=$$?; \ + rm -fr build; \ + #docker-compose $(COMPOSE_FILE_ARGS) logs; + docker cp $(BUILD):/build .; \ + docker rm -f -v $(BUILD); \ + $(MAKE) down; \ + exit $$status + +lint: DOCKER_RUN_ARGS = --volumes-from=$(BUILD) +lint: build up ## lint the application (static code analysis) + $(INIT_CACHE) + $(call make,lint); \ + status=$$?; \ + docker cp $(BUILD):/build .; \ + $(MAKE) down; \ + exit $$status + +pull: ## download the application image + docker pull $(IMAGE_TO_TEST) + +up: build ## start develop/test environment +ifneq ($(NETWORK_MODE),host) + docker network inspect $(NETWORK_MODE) &> /dev/null || ([ $$? -ne 0 ] && docker network create $(NETWORK_MODE)) +endif + #$(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) pull + #to pull only the mid-cbf-mcs image remove comment on row below. + #docker pull $(DOCKER_REGISTRY_HOST)/$(DOCKER_REGISTRY_USER)/mid-cbf-mcs:latest + $(DOCKER_COMPOSE_ARGS) docker-compose -f se-tangodb.yml up -d + # put a sleep to wait TANGO DB + @sleep 10 + $(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) up -d + +piplock: build ## overwrite Pipfile.lock with the image version + docker run $(IMAGE_TO_TEST) cat /app/Pipfile.lock > $(CURDIR)/Pipfile.lock + +interactive: up +interactive: ## start an interactive session using the project image (caution: R/W mounts source directory to /app) + docker run --rm -it -p 3000:3000 --name=$(CONTAINER_NAME_PREFIX)dev -e TANGO_HOST=$(TANGO_HOST) --network=$(NETWORK_MODE) \ + -v $(CURDIR):/app $(IMAGE_TO_TEST) /bin/bash + +down: ## stop develop/test environment and any interactive session + docker ps | grep $(CONTAINER_NAME_PREFIX)dev && docker stop $(PROJECT)-dev || true + $(DOCKER_COMPOSE_ARGS) docker-compose $(COMPOSE_FILE_ARGS) down +ifneq ($(NETWORK_MODE),host) + docker network inspect $(NETWORK_MODE) &> /dev/null && ([ $$? -eq 0 ] && docker network rm $(NETWORK_MODE)) || true +endif + +dsconfigdump: up ## dump the entire configuration to the file dsconfig.json + docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump python -m dsconfig.dump + docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump python -m dsconfig.dump > dsconfig.json + +dsconfigadd: up ## Add a configuration json file (environment variable DSCONFIG_JSON_FILE) to the database + -docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump json2tango -u -w -a $(DSCONFIG_JSON_FILE) + +dsconfigcheck: up ## check a json file (environment variable DSCONFIG_JSON_FILE) according to the project lib-maxiv-dsconfig json schema + -docker exec -it $(CONTAINER_NAME_PREFIX)dsconfigdump json2tango -a $(DSCONFIG_JSON_FILE) + +help: ## show this help. + @grep -hE '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: all test up down help + +# Creates Docker volume for use as a cache, if it doesn't exist already +INIT_CACHE = \ + docker volume ls | grep $(CACHE_VOLUME) || \ + docker create --name $(CACHE_VOLUME) -v $(CACHE_VOLUME):/cache $(IMAGE_TO_TEST) + +# http://cakoose.com/wiki/gnu_make_thunks +BUILD_GEN = $(shell docker create -v /build $(IMAGE_TO_TEST)) +BUILD = $(eval BUILD := $(BUILD_GEN))$(BUILD) diff --git a/docker/config/csplmc_dsconfig.json b/docker/config/csplmc_dsconfig.json new file mode 100644 index 0000000..83dbae6 --- /dev/null +++ b/docker/config/csplmc_dsconfig.json @@ -0,0 +1,240 @@ +{ + "servers": { + "CspSubElementMaster": { + "master": { + "CspSubElementMaster": { + "subelement/sub_elt/master": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ], + "__value": [ + "0" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "Rack": [ + "subelement/rack/01", + "subelement/rack/02", + "subelement/rack/03", + "subelement/rack/04" + ], + "polled_attr": [ + "healthstate", + "1000", + "adminmode", + "1000", + "state", + "1000", + "oncommandprogress", + "2000", + "offcommandprogress", + "2000", + "standbycommandprogress", + "2000", + "oncmdtimeoutexpired", + "1000", + "offcmdtimeoutexpired", + "1000", + "standbycmdtimeoutexpired", + "1000", + "oncmdfailure", + "1000", + "offcmdfailure", + "1000", + "standbycmdfailure", + "1000" + ] + } + } + } + } + }, + "CspCapabilityMonitor": { + "searchbeams": { + "CspCapabilityMonitor": { + "subelement/capability/pss_pipeline_monitor": { + "attribute_properties": { + "adminMode": { + "__value": [ + "0" + ] + } + }, + "properties": { + "CapabilityDevices": [ + "subelement/pipelines/0001", + "subelement/pipelines/0002", + "subelement/pipelines/0003" + ] + } + } + } + }, + "timingbeams": { + "CspCapabilityMonitor": { + "subelement/capability/pstbeams_monitor": { + "attribute_properties": { + "adminMode": { + "__value": [ + "0" + ] + } + }, + "properties": { + "CapabilityDevices": [ + "subelement/pstbeam/01", + "subelement/pstbeam/02", + "subelement/pstbeam/03" + ] + } + } + } + }, + "vlbibeams": { + "CspCapabilityMonitor": { + "subelement/capability/vlbi_beams_monitor": { + "attribute_properties": { + "adminMode": { + "__value": [ + "0" + ] + } + }, + "properties": { + "CapabilityDevices": [ + "subelement/vlbi_beam/01", + "subelement/vlbi_beam/02", + "subelement/vlbi_beam/03" + ] + } + } + } + } + }, + "CspSubElementSubarray": { + "subarray1": { + "CspSubElementSubarray": { + "subelement/sub_elt/subarray_01": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ], + "__value": [ + "0" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "obsState": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "SubID": [ + "1" + ], + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "obsstate", + "1000", + "obsmode", + "1000" + ] + } + } + } + }, + "subarray2": { + "SubElementSubarray": { + "subelement/sub_elt/subarray_02": { + "attribute_properties": { + "adminMode": { + "abs_change": [ + "-1", + "1" + ], + "__value": [ + "0" + ] + }, + "healthState": { + "abs_change": [ + "-1", + "1" + ] + }, + "obsState": { + "abs_change": [ + "-1", + "1" + ] + } + }, + "properties": { + "SubID": [ + "2" + ], + "polled_attr": [ + "state", + "1000", + "healthstate", + "1000", + "adminmode", + "1000", + "obsstate", + "1000", + "obsmode", + "1000" + ] + } + } + } + } + }, + "DataBaseds": { + "2": { + "DataBase": { + "sys/database/2": {} + } + } + }, + "TangoAccessControl": { + "1": { + "TangoAccessControl": { + "sys/access_control/1": {} + } + } + }, + "TangoTest": { + "test": { + "TangoTest": { + "sys/tg_test/1": {} + } + } + } + } +} diff --git a/docker/se-lmc.yml b/docker/se-lmc.yml new file mode 100644 index 0000000..af6db57 --- /dev/null +++ b/docker/se-lmc.yml @@ -0,0 +1,67 @@ +# +# Docker compose file for TANGO database and database device server +# +# Defines: +# - tangodb: MariaDB database with TANGO schema +# - databaseds: TANGO database device server +# - rsyslog-csplmc: rsyslog service for logger +# - cspmaster: CspMaster device +# +# Requires: +# - None +# +version: '2.2' + +services: + se_dsconfig: + image: nexus.engageska-portugal.pt/ska-docker/tango-dsconfig:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}se_dsconfig + depends_on: + - databaseds + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=60 --strict -- + json2tango -w -a -u data/config/csplmc_dsconfig.json && sleep infinity" + volumes: + - .:/data + + sesubarray01: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-subelement:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}sesubarray01 + depends_on: + - se_dsconfig + - semaster + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + retry --max=5 -- tango_admin --ping-device subelement/sub_elt/master &&\ + /venv/bin/python -m cspse.lmc.SubElementSubarray subarray1" + sesubarray02: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-subelement:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}sesubarray02 + depends_on: + - se_dsconfig + - semaster + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- + retry --max=5 -- tango_admin --ping-device subelement/sub_elt/master &&\ + /venv/bin/python -m cspse.lmc.SubElementSubarray subarray2" + + semaster: + image: ${DOCKER_REGISTRY_HOST}/${DOCKER_REGISTRY_USER}/csp-lmc-subelement:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}semaster + depends_on: + - se_dsconfig + environment: + - TANGO_HOST=${TANGO_HOST} + command: > + sh -c "wait-for-it.sh ${TANGO_HOST} --timeout=30 --strict -- CspSubElementMaster master" + diff --git a/docker/se-tangodb.yml b/docker/se-tangodb.yml new file mode 100644 index 0000000..72090df --- /dev/null +++ b/docker/se-tangodb.yml @@ -0,0 +1,50 @@ +# +# Docker compose file for TANGO database and database device server +# +# Defines: +# - tangodb: MariaDB database with TANGO schema +# - databaseds: TANGO database device server +# +# Requires: +# - None +# +version: '2.2' +volumes: + se-tangodb: {} + +services: + tangodb: + image: nexus.engageska-portugal.pt/ska-docker/tango-db:latest + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}tangodb + environment: + - MYSQL_ROOT_PASSWORD=secret + - MYSQL_DATABASE=tango + - MYSQL_USER=tango + - MYSQL_PASSWORD=tango + volumes: + - se-tangodb:/var/lib/mysql + + databaseds: + image: nexus.engageska-portugal.pt/ska-docker/tango-cpp:latest + depends_on: + - tangodb + network_mode: ${NETWORK_MODE} + container_name: ${CONTAINER_NAME_PREFIX}databaseds + environment: + - MYSQL_HOST=${MYSQL_HOST} + - MYSQL_DATABASE=tango + - MYSQL_USER=tango + - MYSQL_PASSWORD=tango + - TANGO_HOST=${TANGO_HOST} + entrypoint: + - /usr/local/bin/wait-for-it.sh + - ${MYSQL_HOST} + - --timeout=70 + - --strict + - -- + - /usr/local/bin/DataBaseds + - "2" + - -ORBendPoint + - giop:tcp::10000 + diff --git a/docker/test-harness/Makefile b/docker/test-harness/Makefile new file mode 100644 index 0000000..f951fe0 --- /dev/null +++ b/docker/test-harness/Makefile @@ -0,0 +1,31 @@ +# Use bash shell with pipefail option enabled so that the return status of a +# piped command is the value of the last (rightmost) commnand to exit with a +# non-zero status. This lets us pipe output into tee but still exit on test +# failures. +SHELL = /bin/bash +.SHELLFLAGS = -o pipefail -c + +all: test lint + +# wait for the device to be available before beginning the test +# A temporary volume is mounted at /build when 'make test' is executing. +# The following steps copy across useful output to this volume which can +# then be extracted to form the CI summary for the test procedure. +test: + # option -k 'dir_name' excludes 'dir_name' contents + cd /app && python setup.py test | tee setup_py_test.stdout + mkdir -p /build/reports && \ + if [ -d /build ]; then \ + mv /app/setup_py_test.stdout /build/csp-lmc-subelement-setup-test.stdout; \ + mv /app/htmlcov /build/csp-lmc-subelement_htmlcov; \ + mv /app/build/reports/csp-lmc-subelement-unit-tests.xml /build/reports; \ + mv /app/coverage.xml /build; \ + fi; +lint: + pip3 install pylint2junit; \ + mkdir -p /build/reports; \ + cd /app && pylint --output-format=parseable csp_lmc_common | tee /build/csp-lmc-subelement-code-analysis.stdout; \ + cd /app && pylint --output-format=pylint2junit.JunitReporter cspse/lmc > /build/reports/csp-lmc-subelement-linting.xml; + +.PHONY: all test lint + diff --git a/docker/test-harness/README.md b/docker/test-harness/README.md new file mode 100644 index 0000000..a3c9a49 --- /dev/null +++ b/docker/test-harness/README.md @@ -0,0 +1,3 @@ +This directory is uploaded to the container when 'make test' is executed. Files +in this directory will be found inside /build once uploaded to the container. + diff --git a/setup.cfg b/setup.cfg index 428ca67..90ecf57 100644 --- a/setup.cfg +++ b/setup.cfg @@ -11,8 +11,16 @@ source = cspse [tool:pytest] testpaths = tests -addopts = --cov --json-report --json-report-file=htmlcov/report.json --cov-report term --cov-report html --cov-report xml --pylint --pylint-error-types=EF --junitxml=./build/reports/unit-tests.xml +addopts = --cov=cspse + --json-report + --json-report-file=htmlcov/report.json + --cov-report=term + --cov-report=html + --cov-report=xml + --junitxml=build/reports/csp-lmc-subelement-unit-tests.xml +junit_family=legacy +console_output_style = progress # Define `python setup.py build_sphinx` [build_sphinx] source-dir = docs diff --git a/setup.py b/setup.py index 0f0f99b..25947e6 100644 --- a/setup.py +++ b/setup.py @@ -1,16 +1,25 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -from setuptools import setup +import os +import sys +from setuptools import setup, find_packages + +setup_dir = os.path.dirname(os.path.abspath(__file__)) + +# make sure we use latest info from local code +sys.path.insert(0, setup_dir) + +INFO = {} with open('README.md') as readme_file: - readme = readme_file.read() + long_description = readme_file.read() RELEASE_FILENAME = os.path.join(setup_dir, 'cspse','lmc','release.py') exec(open(RELEASE_FILENAME).read(), INFO) setup( - name=INFO['name'] - version=INFO['version'] + name=INFO['name'], + version=INFO['version'], description=INFO['description'], author=INFO['author'], author_email=INFO['author_email'], @@ -20,7 +29,6 @@ setup( long_description=long_description, keywords="csp lmc ska tango", include_package_data=True, - license="BSD license", zip_safe=False, classifiers=[ 'Development Status :: 3 - Alpha', @@ -34,7 +42,7 @@ setup( install_requires=[ 'pytango >=9.3.1', 'future', - 'lmcbaseclasses > 0.5.0', + 'csp-lmc-common > 0.5.0', ], setup_requires=[ # dependency for `python setup.py test` @@ -50,6 +58,11 @@ setup( 'pycodestyle', 'mock' ], + entry_points={ + "console_scripts": [ + "CspSubElementMaster=cspse.lmc.subelement_master:main", + ] + }, extras_require={ 'dev': ['prospector[with_pyroma]', 'yapf', 'isort'], } -- GitLab From b08f2369d1d82bb757f697dc9dd6016eb77d718c Mon Sep 17 00:00:00 2001 From: softir Date: Thu, 2 Apr 2020 16:30:11 +0200 Subject: [PATCH 03/17] AT5-370: Added decorators to check device State before command execution. --- .pylintrc | 4 +- cspse/lmc/decorators.py | 108 +++++++++++++++++++++++++++++++++ cspse/lmc/subelement_master.py | 65 ++++---------------- tests/test_ska_skeleton.py | 40 ------------ 4 files changed, 123 insertions(+), 94 deletions(-) create mode 100644 cspse/lmc/decorators.py delete mode 100644 tests/test_ska_skeleton.py diff --git a/.pylintrc b/.pylintrc index eae6a06..a708e2a 100644 --- a/.pylintrc +++ b/.pylintrc @@ -28,7 +28,7 @@ limit-inference-results=100 # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. -load-plugins=pylint_junit +load-plugins= # Pickle collected data for later comparisons. persistent=yes @@ -95,7 +95,7 @@ evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / stateme # Set the output format. Available formats are text, parseable, colorized, json # and msvs (visual studio). You can also give a reporter class, e.g. # mypackage.mymodule.MyReporterClass. -output-format=junit +output-format=text # Tells whether to display a full report or only the messages. reports=yes diff --git a/cspse/lmc/decorators.py b/cspse/lmc/decorators.py new file mode 100644 index 0000000..1fe7555 --- /dev/null +++ b/cspse/lmc/decorators.py @@ -0,0 +1,108 @@ +import functools +import tango + +tasks = {} + +# note: f.__name__ is of type is_XXX_allowed +# f.__name__[3:-8] select the command name +# this decorator build a dictionary with the command name as key and +# the handler as value. +task = lambda f:tasks.setdefault(f.__name__[3:-8], f) + +@task +def is_standby_allowed(device_instance): + """ + Allowed method for Standby method. + Command *Standby* is allowed when the device *State* is ON or + STANDBY. + + :return: True if the method is allowed, otherwise False. + """ + if device_instance.get_state() in [tango.DevState.ON, + tango.DevState.STANDBY]: + return True + return False + +@task +def is_on_allowed(device_instance): + """ + Allowed method for On method. + Command *On* is allowed when the device *State* is ON or + STANDBY. + + :return: True if the method is allowed, otherwise False. + """ + if device_instance.get_state() in [tango.DevState.ON, + tango.DevState.STANDBY]: + return True + return False + +@task +def is_off_allowed(device_instance): + """ + Allowed method for Off method. + Command *Off* is allowed when the device *State* is OFF or + STANDBY. + + :return: True if the method is allowed, otherwise False. + """ + if device_instance.get_state() in [tango.DevState.OFF, + tango.DevState.STANDBY]: + return True + return False + +def is_command_allowed(device_instance, cmd_name): + """ + Call the allowed method for the command name specified + as input argument + :param device_istance: the TANGO device instance + :param cmd_name: the name of command to execute + + :return: True/False + """ + tasks[cmd_name](device_instance) + +class IsCommandAllowed(object): + """ + Class designed to be a decorator for the Master power methods. + The *decorator function* performs a check on the input argument + to control if the command is issued on the whole sub-element. + If this is the case, it checks the State of the sub-element Master + device and rejects the command accordingly to the State + machine setting. + + :raise: tango.DevFailed exception if the command can't be executed + """ + def __init__(self, *args, **kwargs): + # store the decorators parameters: + # args: the list of sub-element attributes to subscribe, to track the + # sub-element command progress and detect a command timeout + # kwargs: a dictionary: key ="cmd_name", + # value = command to execute ('on', 'off'...) + self._args = args + self._kwargs = kwargs + + def __call__(self, f): + @functools.wraps(f) + def input_args_check(*args, **kwargs): + # the Master device instance + dev_instance = args[0] + # the command name + cmd_to_exec = f.__name__ + # the command input argument + input_arg = args[1] + device_list = input_arg + # Note: device list is a reference to args[1]: changing + # device_list content, args[1] changes accordingly! + num_of_devices = len(input_arg) + if num_of_devices == 0: + # check the device State: if it not the proper value the command is + # not executed + if not is_command_allowed(dev_instance, cmd_to_exec.lower()): + msg = "Command {} can't be executed when the device is {}".format(cmd_to_exec, + dev_instance.get_state()) + tango.Except.throw_exception("Command failure",msg, + "IsCommandAllowed decorator", + tango.ErrSeverity.ERR) + return f(*args, **kwargs) + return input_args_check diff --git a/cspse/lmc/subelement_master.py b/cspse/lmc/subelement_master.py index 9cabff7..1ae381c 100644 --- a/cspse/lmc/subelement_master.py +++ b/cspse/lmc/subelement_master.py @@ -24,9 +24,12 @@ from tango import AttrWriteType, PipeWriteType from collections import defaultdict # Additional import # PROTECTED REGION ID(CspSubElementMaster.additionnal_import) ENABLED START # -from ska.base.SKAMaster import SKAMaster +from ska.base import SKAMaster from ska.base.control_model import HealthState, AdminMode, LoggingLevel -from csp_lmc_common.cspcommons.utils import CmdExecState +from csp_lmc_common.utils.cspcommons import CmdExecState +from csp_lmc_common.utils.decorators import AdminModeCheck +from .decorators import IsCommandAllowed +from . import release # PROTECTED REGION END # // CspSubElementMaster.additionnal_import __all__ = ["CspSubElementMaster", "main"] @@ -198,7 +201,6 @@ class CspSubElementMaster(SKAMaster): dtype='DevBoolean', label="On execution timeout flag", polling_period=2000, - abs_change=1, doc="Signal the occurence of a timeout during the execution of the on command.", ) @@ -206,7 +208,6 @@ class CspSubElementMaster(SKAMaster): dtype='DevBoolean', label="Off execution timeout flag", polling_period=2000, - abs_change=1, doc="Signal the occurence of a timeout during the execution of the Off command.", ) @@ -214,7 +215,6 @@ class CspSubElementMaster(SKAMaster): dtype='DevBoolean', label="Standby execution timeout flag.", polling_period=2000, - abs_change=1, doc="Signal the occurence of a timeout during the execution of the Standby command.", ) @@ -239,6 +239,7 @@ class CspSubElementMaster(SKAMaster): def init_device(self): """Initialises the attributes and properties of the CspSubElementMaster.""" SKAMaster.init_device(self) + self.set_state(tango.DevState.INIT) # PROTECTED REGION ID(CspSubElementMaster.init_device) ENABLED START # # PROTECTED REGION ID(CspSubElementMaster.init_device) ENABLED START # # _cmd_execution_state: implement the execution state of a long-running @@ -441,7 +442,7 @@ class CspSubElementMaster(SKAMaster): def read_onCmdDurationMeasured(self): # PROTECTED REGION ID(CspSubElementMaster.onCmdDurationMeasured_read) ENABLED START # """Return the onCmdDurationMeasured attribute.""" - return self._cmd_duration_measured['on']return self._cmd_duration_measured['on'] + return self._cmd_duration_measured['on'] # PROTECTED REGION END # // CspSubElementMaster.onCmdDurationMeasured_read def read_offCmdDurationMeasured(self): @@ -491,21 +492,6 @@ class CspSubElementMaster(SKAMaster): # Commands # -------- - @AdminModeCheck('On') - def is_On_allowed(self): - """ - *TANGO is_allowed method* - - Command *On* is allowed when the device *State* is STANDBY. - - :return: True if the method is allowed, otherwise False. - """ - # PROTECTED REGION ID(CspMaster.is_On_allowed) ENABLED START # - # Note: as per SKA Guidelines, the command is allowed when - if self.get_state() not in [tango.DevState.STANDBY, tango.DevState.ON]: - return False - return True - @command( dtype_in='DevVarStringArray', doc_in="The list of sub-element components FQDNs to switch-on or an empty list to switch-on the whole " @@ -516,6 +502,8 @@ class CspSubElementMaster(SKAMaster): "CSP SubElement component to switch ON.", ) @DebugIt() + @IsCommandAllowed() + @AdminModeCheck('On') def On(self, argin): # PROTECTED REGION ID(CspSubElementMaster.On) ENABLED START # """ @@ -538,21 +526,6 @@ class CspSubElementMaster(SKAMaster): pass # PROTECTED REGION END # // CspSubElementMaster.On - @AdminModeCheck('Off') - def is_Off_allowed(self): - """ - *TANGO is_allowed method* - - Command *Off* is allowed when the device *State* is STANDBY. - - :return: True if the method is allowed, otherwise False. - """ - # PROTECTED REGION ID(CspMaster.is_On_allowed) ENABLED START # - # Note: as per SKA Guidelines, the command is allowed when - if self.get_state() not in [tango.DevState.STANDBY, tango.DevState.OFF]: - return False - return True - @command( dtype_in='DevVarStringArray', doc_in="If the array length is 0, the command applies to the whole" @@ -561,6 +534,8 @@ class CspSubElementMaster(SKAMaster): "CSP SubElement component to switch OFF.", ) @DebugIt() + @IsCommandAllowed() + @AdminModeCheck('Off') def Off(self, argin): # PROTECTED REGION ID(CspSubElementMaster.Off) ENABLED START # """ @@ -579,21 +554,6 @@ class CspSubElementMaster(SKAMaster): pass # PROTECTED REGION END # // CspSubElementMaster.Off - @AdminModeCheck('Standby') - def is_Standby_allowed(self): - """ - *TANGO is_allowed method* - - Command *Standby* is allowed when the device *State* is ON. - - :return: True if the method is allowed, otherwise False. - """ - # PROTECTED REGION ID(CspMaster.is_On_allowed) ENABLED START # - # Note: as per SKA Guidelines, the command is allowed when - if self.get_state() not in [tango.DevState.STANDBY, tango.DevState.ON]: - return False - return True - @command( dtype_in='DevVarStringArray', doc_in="If the array length is 0, the command applies to the whole" @@ -602,6 +562,8 @@ class CspSubElementMaster(SKAMaster): "CSP SubElement icomponent to put in STANDBY mode.", ) @DebugIt() + @IsCommandAllowed() + @AdminModeCheck('Standby') def Standby(self, argin): # PROTECTED REGION ID(CspSubElementMaster.Standby) ENABLED START # """ @@ -635,7 +597,6 @@ class CspSubElementMaster(SKAMaster): # Run server # ---------- - def main(args=None, **kwargs): """Main function of the CspSubElementMaster module.""" # PROTECTED REGION ID(CspSubElementMaster.main) ENABLED START # diff --git a/tests/test_ska_skeleton.py b/tests/test_ska_skeleton.py deleted file mode 100644 index 553d179..0000000 --- a/tests/test_ska_skeleton.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -"""Tests for the ska_python_skeleton module.""" -import pytest - -from ska_python_skeleton import ska_python_skeleton - - -# TODO: Replace all the following examples with tests for the ska_python_skeleton package code -def test_something(): - """Example: Assert with no defined return value.""" - assert True - - -def test_with_error(): - """Example: Assert raising error.""" - with pytest.raises(ValueError): - # Do something that raises a ValueError - raise ValueError - - -# Fixture example -@pytest.fixture -def an_object(): - """Example: Define fixture for subsequent test.""" - return {} - - -def test_ska_python_skeleton(an_object): - """Example: Assert fixture return value.""" - assert an_object == {} - - -def test_package(): - """Example: Assert the ska_python_skeleton package code.""" - assert ska_python_skeleton.function_example() is None - foo = ska_python_skeleton.SKA() - assert foo.example_2() == 2 - assert foo.example() is None -- GitLab From 00bf1222640ce1338a9f661ddf8c308d0e74d46d Mon Sep 17 00:00:00 2001 From: softir Date: Fri, 3 Apr 2020 13:17:13 +0200 Subject: [PATCH 04/17] AT5-370: Added tests for sub-element master device. Fixed some bugs in device code. --- cspse/lmc/__init__.py | 7 + cspse/lmc/subelement_master.py | 16 +- tests/conftest.py | 65 ++++++++ tests/test_se_master.py | 275 +++++++++++++++++++++++++++++++++ 4 files changed, 355 insertions(+), 8 deletions(-) create mode 100644 tests/conftest.py create mode 100644 tests/test_se_master.py diff --git a/cspse/lmc/__init__.py b/cspse/lmc/__init__.py index e69de29..0fb30f2 100644 --- a/cspse/lmc/__init__.py +++ b/cspse/lmc/__init__.py @@ -0,0 +1,7 @@ +__all__ = ( + "CspSubElementMaster", + "CspSubElementSubarray" +) + +from .subelement_master import CspSubElementMaster + diff --git a/cspse/lmc/subelement_master.py b/cspse/lmc/subelement_master.py index 1ae381c..f20a0c0 100644 --- a/cspse/lmc/subelement_master.py +++ b/cspse/lmc/subelement_master.py @@ -296,10 +296,8 @@ class CspSubElementMaster(SKAMaster): # _list_of_components: report the list of subordinate # sub-element components. - # Implemented as a dictionary - # keys: the command name ('on', 'off',...) - # values: the list of components - self._list_of_components = defaultdict(lambda: []) + # Implemented as a list of FQDNs + self._list_of_components = [] # _num_dev_completed_task: for each long-running command report the number # of subordinate components that completed the task @@ -309,7 +307,7 @@ class CspSubElementMaster(SKAMaster): self._num_dev_completed_task = defaultdict(lambda:0) # the last executed command - self._last_executed_command = "" + self._last_executed_command = "none" # PROTECTED REGION END # // CspSubElementMaster.init_device @@ -334,7 +332,7 @@ class CspSubElementMaster(SKAMaster): def read_numOfDevCompletedTask(self): # PROTECTED REGION ID(CspSubElementMaster.numOfDevCompletedTask_read) ENABLED START # """Return the numOfDevCompletedTask attribute.""" - return self._num_dev_completed_task + return self._num_dev_completed_task[self._last_executed_command] # PROTECTED REGION END # // CspSubElementMaster.numOfDevCompletedTask_read def read_onCmdFailure(self): @@ -364,7 +362,7 @@ class CspSubElementMaster(SKAMaster): def read_standbyCmdFailure(self): # PROTECTED REGION ID(CspSubElementMaster.standbyCmdFailure_read) ENABLED START # """Return the standbyCmdFailure attribute.""" - return self._failure_message['standby'] + return self._failure_raised['standby'] # PROTECTED REGION END # // CspSubElementMaster.standbyCmdFailure_read def read_standbyFailureMessage(self): @@ -383,6 +381,8 @@ class CspSubElementMaster(SKAMaster): # PROTECTED REGION ID(CspSubElementMaster.adminMode_write) ENABLED START # """Set the adminMode attribute.""" self._admin_mode = value + if self._admin_mode not in [AdminMode.ONLINE, AdminMode.MAINTENANCE]: + self.set_state(tango.DevState.DISABLE) # PROTECTED REGION END # // CspSubElementMaster.adminMode_write def read_onCommandProgress(self): @@ -479,7 +479,7 @@ class CspSubElementMaster(SKAMaster): def read_listOfDevCompletedTask(self): # PROTECTED REGION ID(CspSubElementMaster.listOfDevCompletedTask_read) ENABLED START # """Return the listOfDevCompletedTask attribute.""" - return self._list_dev_completed_task + return self._list_dev_completed_task[self._last_executed_command] # PROTECTED REGION END # // CspSubElementMaster.listOfDevCompletedTask_read def read_listOfComponents(self): diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..69c7a6d --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,65 @@ +""" +A module defining a list of fixtures that are shared across tests. +""" +import importlib +import pytest + +from tango.test_context import DeviceTestContext + + +@pytest.fixture(scope="class") +def tango_context(request): + """Creates and returns a TANGO DeviceTestContext object. + + Parameters + ---------- + request: _pytest.fixtures.SubRequest + A request object gives access to the requesting test context. + """ + test_properties = { + 'CspSubElementMaster': { + 'SkaLevel': '4', + 'LoggingTargetsDefault': '', + 'GroupDefinitions': '', + 'NrSubarrays': '16', + 'CapabilityTypes': '', + 'MaxCapabilities': ['VCC:197', 'FSP:27'] + }, + + 'CspSubElementSubarray': { + 'CapabilityTypes': ['VCC','FSP'], + 'LoggingTargetsDefault': '', + 'GroupDefinitions': '', + 'SkaLevel': '4', + 'SubID': '1', + }, + } + + # This fixture is used to decorate classes like "TestSKABaseDevice" or + # "TestSKALogger". We drop the first "Test" from the string to get the + # class name of the device under test. + # Similarly, the test module is like "test_base_device.py". We drop the + # first "test_" to get the module name + test_class_name = request.cls.__name__ + class_name = test_class_name.split('Test', 1)[-1] + print("class_name:", class_name) + module = importlib.import_module("cspse.lmc", class_name) + class_type = getattr(module, class_name) + + tango_context = DeviceTestContext(class_type, properties=test_properties.get(class_name)) + tango_context.start() + yield tango_context + tango_context.stop() + + +@pytest.fixture(scope="function") +def initialize_device(tango_context): + """Re-initializes the device. + + Parameters + ---------- + tango_context: tango.test_context.DeviceTestContext + Context to run a device without a database. + """ + print("Sono qui") + yield tango_context.device.Init() diff --git a/tests/test_se_master.py b/tests/test_se_master.py new file mode 100644 index 0000000..94d9e4b --- /dev/null +++ b/tests/test_se_master.py @@ -0,0 +1,275 @@ +# +# -*- coding: utf-8 -*- +# +# This file is part of the CspSubElementMaster project +# +"""Contain the tests for the Master.""" + +# Standard imports +import sys +import os +import time + +# Imports +import re +import pytest +from tango import DevState +from tango import DevFailed + +# PROTECTED REGION ID(CspSubElementMaster.test_additional_imports) ENABLED START # +from ska.base.control_model import AdminMode, ControlMode, HealthState, SimulationMode, TestMode +# PROTECTED REGION END # // CspSubElementMaster.test_additional_imports +# Device test case +# PROTECTED REGION ID(CspSubElementMaster.test_CspSubElementMaster_decorators) ENABLED START # +@pytest.mark.usefixtures("tango_context") +# PROTECTED REGION END # // CspSubElementMaster.test_CspSubElementMaster_decorators +class TestCspSubElementMaster(object): + """Test case for packet generation.""" + + capabilities = ['FSP:27', 'VCC:197'] + properties = { + 'SkaLevel': '4', + 'LoggingTargetsDefault': '', + 'GroupDefinitions': '', + 'NrSubarrays': '16', + 'CapabilityTypes': '', + 'MaxCapabilities': ['FSP:27', 'VCC:197'] + } + + @classmethod + def mocking(cls): + """Mock external libraries.""" + # Example : Mock numpy + # cls.numpy = CspSubElementMaster.numpy = MagicMock() + # PROTECTED REGION ID(CspSubElementMaster.test_mocking) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_mocking + + def test_properties(self, tango_context): + # Test the properties + # PROTECTED REGION ID(CspSubElementMaster.test_properties) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_properties + pass + + # PROTECTED REGION ID(CspSubElementMaster.test_State_decorators) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_State_decorators + def test_State(self, tango_context): + """Test for State""" + # PROTECTED REGION ID(CspSubElementMaster.test_State) ENABLED START # + assert tango_context.device.State() == DevState.INIT + # PROTECTED REGION END # // CspSubElementMaster.test_State + + # PROTECTED REGION ID(CspSubElementMaster.test_Status_decorators) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_Status_decorators + def test_Status(self, tango_context): + """Test for Status""" + # PROTECTED REGION ID(CspSubElementMaster.test_Status) ENABLED START # + assert tango_context.device.Status() == "The device is in INIT state." + # PROTECTED REGION END # // CspSubElementMaster.test_Status + + # PROTECTED REGION ID(CspSubElementMaster.test_GetVersionInfo_decorators) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_GetVersionInfo_decorators + def test_GetVersionInfo(self, tango_context): + """Test for GetVersionInfo""" + # PROTECTED REGION ID(CspSubElementMaster.test_GetVersionInfo) ENABLED START # + versionPattern = re.compile( + r'CspSubElementMaster, lmcbaseclasses, [0-9].[0-9].[0-9], ' + r'A set of generic base devices for SKA Telescope.') + versionInfo = tango_context.device.GetVersionInfo() + assert (re.match(versionPattern, versionInfo[0])) != None + # PROTECTED REGION END # // CspSubElementMaster.test_GetVersionInfo + + + # PROTECTED REGION ID(CspSubElementMaster.test_buildState_decorators) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_buildState_decorators + def test_buildState(self, tango_context): + """Test for buildState""" + # PROTECTED REGION ID(CspSubElementMaster.test_buildState) ENABLED START # + buildPattern = re.compile( + r'lmcbaseclasses, [0-9].[0-9].[0-9], ' + r'A set of generic base devices for SKA Telescope') + assert (re.match(buildPattern, tango_context.device.buildState)) != None + # PROTECTED REGION END # // CspSubElementMaster.test_buildState + + # PROTECTED REGION ID(CspSubElementMaster.test_versionId_decorators) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_versionId_decorators + def test_versionId(self, tango_context): + """Test for versionId""" + # PROTECTED REGION ID(CspSubElementMaster.test_versionId) ENABLED START # + versionIdPattern = re.compile(r'[0-9].[0-9].[0-9]') + assert (re.match(versionIdPattern, tango_context.device.versionId)) != None + # PROTECTED REGION END # // CspSubElementMaster.test_versionId + + # PROTECTED REGION ID(CspSubElementMaster.test_healthState_decorators) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_healthState_decorators + def test_healthState(self, tango_context): + """Test for healthState""" + # PROTECTED REGION ID(CspSubElementMaster.test_healthState) ENABLED START # + assert tango_context.device.healthState == HealthState.OK + # PROTECTED REGION END # // CspSubElementMaster.test_healthState + + # PROTECTED REGION ID(CspSubElementMaster.test_adminMode_decorators) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_adminMode_decorators + def test_adminMode(self, tango_context): + """Test for adminMode""" + # PROTECTED REGION ID(CspSubElementMaster.test_adminMode) ENABLED START # + assert tango_context.device.adminMode == AdminMode.ONLINE + # PROTECTED REGION END # // CspSubElementMaster.test_adminMode + + # PROTECTED REGION ID(CspSubElementMaster.test_write_adminMode_decorators) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_adminMode_decorators + def test_write_adminMode(self, tango_context): + """Test for adminMode""" + # PROTECTED REGION ID(CspSubElementMaster.test_adminMode) ENABLED START # + tango_context.device.adminMode = AdminMode.OFFLINE + time.sleep(2) + assert tango_context.device.adminMode == AdminMode.OFFLINE + assert tango_context.device.State() == DevState.DISABLE + # PROTECTED REGION END # // CspSubElementMaster.test_adminMode + + # PROTECTED REGION ID(CspSubElementMaster.test_On_invalid_adminModedecorators) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_On_invalid_adminMode decorators + def test_On_invalid_adminMode(self, tango_context): + """Test On command with offline adminmode""" + # PROTECTED REGION ID(CspSubElementMaster.test_On_invalid_adminMode) ENABLED START # + with pytest.raises(DevFailed) as df: + argin = [""] + tango_context.device.On(argin) + assert "On command can't" in str(df.value.args[0].desc) + # PROTECTED REGION END # // CspSubElementMaster.test_On_invalid_adminMode + + # PROTECTED REGION ID(CspSubElementMaster.test_Off_invalid_adminModedecorators) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_Off_invalid_adminMode decorators + def test_Off_invalid_adminMode(self, tango_context): + """Test Off command with offline adminmode""" + # PROTECTED REGION ID(CspSubElementMaster.test_Off_invalid_adminMode) ENABLED START # + with pytest.raises(DevFailed) as df: + argin = [""] + tango_context.device.Off(argin) + assert "Off command can't" in str(df.value.args[0].desc) + # PROTECTED REGION END # // CspSubElementMaster.test_Off_invalid_adminMode + + # PROTECTED REGION ID(CspSubElementMaster.test_Standby_invalid_adminModedecorators) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_Standby_invalid_adminMode decorators + def test_Standby_invalid_adminMode(self, tango_context): + """Test Standby command with offline adminmode""" + # PROTECTED REGION ID(CspSubElementMaster.test_Standby_invalid_adminMode) ENABLED START # + with pytest.raises(DevFailed) as df: + argin = [""] + tango_context.device.Standby(argin) + assert "Standby command can't" in str(df.value.args[0].desc) + # PROTECTED REGION END # // CspSubElementMaster.test_Standby_invalid_adminMode + + # PROTECTED REGION ID(CspSubElementMaster.test_On_invalid_Statedecorators) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_On_invalid_State decorators + def test_On_invalid_State(self, tango_context): + """Test On command with offline adminmode""" + # PROTECTED REGION ID(CspSubElementMaster.test_On_invalid_State) ENABLED START # + # set the adminMode to ONLINE + # reinitialize the device to return to + # adminMode =ONLINE and State=INIT + tango_context.device.Init() + time.sleep(2) + assert tango_context.device.adminMode == AdminMode.ONLINE + assert tango_context.device.State() == DevState.INIT + with pytest.raises(DevFailed) as df: + argin = [] + tango_context.device.On(argin) + assert "Command On can't" in str(df.value.args[0].desc) + # PROTECTED REGION END # // CspSubElementMaster.test_On_invalid_State + + # PROTECTED REGION ID(CspSubElementMaster.test_Off_invalid_Statedecorators) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_Off_invalid_State decorators + def test_Off_invalid_State(self, tango_context): + """Test Off command with offline adminmode""" + # PROTECTED REGION ID(CspSubElementMaster.test_Off_invalid_State) ENABLED START # + assert tango_context.device.adminMode == AdminMode.ONLINE + with pytest.raises(DevFailed) as df: + argin = [] + tango_context.device.Off(argin) + assert "Command Off can't" in str(df.value.args[0].desc) + # PROTECTED REGION END # // CspSubElementMaster.test_Off_invalid_State + + # PROTECTED REGION ID(CspSubElementMaster.test_Standby_invalid_Statedecorators) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_Standby_invalid_State decorators + def test_Standby_invalid_State(self, tango_context): + """Test Standby command with offline adminmode""" + # PROTECTED REGION ID(CspSubElementMaster.test_Standby_invalid_State) ENABLED START # + assert tango_context.device.adminMode == AdminMode.ONLINE + with pytest.raises(DevFailed) as df: + argin = [] + tango_context.device.Standby(argin) + assert "Command Standby can't" in str(df.value.args[0].desc) + # PROTECTED REGION END # // CspSubElementMaster.test_Standby_invalid_State + + # PROTECTED REGION ID(CspSubElementMaster.test_controlMode_decorators) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_controlMode_decorators + def test_controlMode(self, tango_context): + """Test for controlMode""" + # PROTECTED REGION ID(CspSubElementMaster.test_controlMode) ENABLED START # + assert tango_context.device.controlMode == ControlMode.REMOTE + # PROTECTED REGION END # // CspSubElementMaster.test_controlMode + + # PROTECTED REGION ID(CspSubElementMaster.test_maxCapabilities_decorators) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_maxCapabilities_decorators + def test_maxCapabilities(self, tango_context): + """Test for maxCapabilities""" + # PROTECTED REGION ID(CspSubElementMaster.test_maxCapabilities) ENABLED START # + assert tango_context.device.maxCapabilities == ('FSP:27', 'VCC:197') + # PROTECTED REGION END # // CspSubElementMaster.test_maxCapabilities + + # PROTECTED REGION ID(CspSubElementMaster.test_availableCapabilities_decorators) ENABLED START # + # PROTECTED REGION END # // CspSubElementMaster.test_availableCapabilities_decorators + def test_availableCapabilities(self, tango_context): + """Test for availableCapabilities""" + # PROTECTED REGION ID(CspSubElementMaster.test_availableCapabilities) ENABLED START # + assert tango_context.device.availableCapabilities == ('FSP:27', 'VCC:197') + # PROTECTED REGION END # // CspSubElementMaster.test_availableCapabilities + + def test_num_of_dev_completed_task(self, tango_context): + """Test numOfCompletedTask attribute""" + assert tango_context.device.numOfDevCompletedTask == 0 + + def test_list_of_completed_task(self, tango_context): + """Test listOfCompletedTask attribute""" + assert tango_context.device.listOfDevCompletedTask == None + + def test_list_of_components(self, tango_context): + """Test listOfComponents attribute""" + assert tango_context.device.listOfComponents == None + + def test_timeout_expired(self, tango_context): + """Test xxxTimeoutExpired flags attribute""" + assert not tango_context.device.onCmdTimeoutExpired + assert not tango_context.device.offCmdTimeoutExpired + assert not tango_context.device.standbyCmdTimeoutExpired + + def test_failure_raised(self, tango_context): + """Test xxxCmdFailure attributes""" + assert not tango_context.device.onCmdFailure + assert not tango_context.device.offCmdFailure + assert not tango_context.device.standbyCmdFailure + + def test_failure_message(self, tango_context): + """Test xxxFailureMessage attributes""" + assert not tango_context.device.onFailureMessage + assert not tango_context.device.offFailureMessage + assert not tango_context.device.standbyFailureMessage + + def test_command_progress(self, tango_context): + """Test xxxCommandProgress attributes""" + assert tango_context.device.onCommandProgress == 0 + assert tango_context.device.offCommandProgress == 0 + assert tango_context.device.standbyCommandProgress == 0 + + def test_command_duration_measured(self, tango_context): + """Test xxxCmdDurationMeasured attributes""" + assert tango_context.device.onCmdDurationMeasured == 0 + assert tango_context.device.offCmdDurationMeasured == 0 + assert tango_context.device.standbyCmdDurationMeasured == 0 + + def test_command_duration_expected(self, tango_context): + """Test xxxCmdDurationExpected attributes""" + assert tango_context.device.onCmdDurationExpected == 30 + assert tango_context.device.offCmdDurationExpected == 30 + assert tango_context.device.standbyCmdDurationExpected == 30 + -- GitLab From ceb44c89abf806105c4bdc1cf37f101a682ef810 Mon Sep 17 00:00:00 2001 From: softir Date: Fri, 3 Apr 2020 16:05:04 +0200 Subject: [PATCH 05/17] AT5-370: Removed default polling value set for some attributes and polling configuration from dsconfig file: if polling is enabled for the attributes, the test on attribute reading is not performed because the value is read from the cache and not from the device. Polling has to be enabled into the dsconfig file when the real devices are instantiated) --- cspse/lmc/subelement_master.py | 18 +++++----- docker/config/csplmc_dsconfig.json | 54 ++---------------------------- pogo/CspSubElementMaster.xmi | 28 ++++++++++------ setup.cfg | 6 +++- tests/test_se_master.py | 12 +++++++ 5 files changed, 44 insertions(+), 74 deletions(-) diff --git a/cspse/lmc/subelement_master.py b/cspse/lmc/subelement_master.py index f20a0c0..b27c0dd 100644 --- a/cspse/lmc/subelement_master.py +++ b/cspse/lmc/subelement_master.py @@ -42,6 +42,9 @@ class CspSubElementMaster(SKAMaster): **Properties:** - Device Property + Racks + - The list with the FQDNs of the sub-element racks devices. + - Type:'DevVarStringArray' """ # PROTECTED REGION ID(CspSubElementMaster.class_variable) ENABLED START # # PROTECTED REGION END # // CspSubElementMaster.class_variable @@ -50,6 +53,10 @@ class CspSubElementMaster(SKAMaster): # Device Properties # ----------------- + Racks = device_property( + dtype='DevVarStringArray', + ) + # ---------- # Attributes # ---------- @@ -63,7 +70,7 @@ class CspSubElementMaster(SKAMaster): onCmdFailure = attribute( dtype='DevBoolean', label="CBF command failure flag", - polling_period=1000, + #polling_period=1000, doc="Failure flag set when the On command fails with error(s).", ) @@ -76,7 +83,6 @@ class CspSubElementMaster(SKAMaster): offCmdFailure = attribute( dtype='DevBoolean', label="Off execution failure flag", - polling_period=1000, doc="Failure flag set when the Off command fails with error(s).", ) @@ -89,7 +95,6 @@ class CspSubElementMaster(SKAMaster): standbyCmdFailure = attribute( dtype='DevBoolean', label="Standby execution failure message", - polling_period=1000, doc="Failure flag set when the Standby command fails with error(s).", ) @@ -102,7 +107,6 @@ class CspSubElementMaster(SKAMaster): adminMode = attribute( dtype=AdminMode, access=AttrWriteType.READ_WRITE, - polling_period=1000, memorized=True, doc="The admin mode reported for this device. It may interpret the current device condition \nand condition of all managed devices to set this. Most possibly an aggregate attribute.", ) @@ -110,7 +114,6 @@ class CspSubElementMaster(SKAMaster): onCommandProgress = attribute( dtype='DevUShort', label="Progress percentage for the On command", - polling_period=3000, abs_change=10, max_value=100, min_value=0, @@ -120,7 +123,6 @@ class CspSubElementMaster(SKAMaster): offCommandProgress = attribute( dtype='DevUShort', label="Progress percentage for the Off command", - polling_period=3000, abs_change=10, max_value=100, min_value=0, @@ -130,7 +132,6 @@ class CspSubElementMaster(SKAMaster): standbyCommandProgress = attribute( dtype='DevUShort', label="Progress percentage for the Standby command", - polling_period=3000, abs_change=10, max_value=100, min_value=0, @@ -200,21 +201,18 @@ class CspSubElementMaster(SKAMaster): onCmdTimeoutExpired = attribute( dtype='DevBoolean', label="On execution timeout flag", - polling_period=2000, doc="Signal the occurence of a timeout during the execution of the on command.", ) offCmdTimeoutExpired = attribute( dtype='DevBoolean', label="Off execution timeout flag", - polling_period=2000, doc="Signal the occurence of a timeout during the execution of the Off command.", ) standbyCmdTimeoutExpired = attribute( dtype='DevBoolean', label="Standby execution timeout flag.", - polling_period=2000, doc="Signal the occurence of a timeout during the execution of the Standby command.", ) diff --git a/docker/config/csplmc_dsconfig.json b/docker/config/csplmc_dsconfig.json index 83dbae6..29d976d 100644 --- a/docker/config/csplmc_dsconfig.json +++ b/docker/config/csplmc_dsconfig.json @@ -27,32 +27,6 @@ "subelement/rack/02", "subelement/rack/03", "subelement/rack/04" - ], - "polled_attr": [ - "healthstate", - "1000", - "adminmode", - "1000", - "state", - "1000", - "oncommandprogress", - "2000", - "offcommandprogress", - "2000", - "standbycommandprogress", - "2000", - "oncmdtimeoutexpired", - "1000", - "offcmdtimeoutexpired", - "1000", - "standbycmdtimeoutexpired", - "1000", - "oncmdfailure", - "1000", - "offcmdfailure", - "1000", - "standbycmdfailure", - "1000" ] } } @@ -151,19 +125,7 @@ "properties": { "SubID": [ "1" - ], - "polled_attr": [ - "state", - "1000", - "healthstate", - "1000", - "adminmode", - "1000", - "obsstate", - "1000", - "obsmode", - "1000" - ] + ] } } } @@ -197,19 +159,7 @@ "properties": { "SubID": [ "2" - ], - "polled_attr": [ - "state", - "1000", - "healthstate", - "1000", - "adminmode", - "1000", - "obsstate", - "1000", - "obsmode", - "1000" - ] + ] } } } diff --git a/pogo/CspSubElementMaster.xmi b/pogo/CspSubElementMaster.xmi index 567b8c2..0abe206 100644 --- a/pogo/CspSubElementMaster.xmi +++ b/pogo/CspSubElementMaster.xmi @@ -1,7 +1,7 @@ - + @@ -38,6 +38,10 @@ + + + + @@ -169,7 +173,7 @@ - + @@ -185,7 +189,7 @@ - + @@ -201,7 +205,7 @@ - + @@ -231,7 +235,7 @@ - + @@ -259,7 +263,7 @@ - + @@ -268,7 +272,7 @@ - + @@ -277,7 +281,7 @@ - + @@ -340,7 +344,7 @@ - + @@ -349,7 +353,7 @@ - + @@ -358,7 +362,7 @@ - + @@ -429,5 +433,7 @@ + + diff --git a/setup.cfg b/setup.cfg index 90ecf57..ed35f2e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -11,7 +11,8 @@ source = cspse [tool:pytest] testpaths = tests -addopts = --cov=cspse +addopts = --verbose + --cov=cspse --json-report --json-report-file=htmlcov/report.json --cov-report=term @@ -21,6 +22,9 @@ addopts = --cov=cspse junit_family=legacy console_output_style = progress + +[coverage:report] +show_missing = True # Define `python setup.py build_sphinx` [build_sphinx] source-dir = docs diff --git a/tests/test_se_master.py b/tests/test_se_master.py index 94d9e4b..a598ec3 100644 --- a/tests/test_se_master.py +++ b/tests/test_se_master.py @@ -273,3 +273,15 @@ class TestCspSubElementMaster(object): assert tango_context.device.offCmdDurationExpected == 30 assert tango_context.device.standbyCmdDurationExpected == 30 + def test_set_command_duration_expected(self, tango_context): + """Test xxxCmdDurationExpected attributes""" + tango_context.device.onCmdDurationExpected = 20 + tango_context.device.offCmdDurationExpected = 20 + tango_context.device.standbyCmdDurationExpected = 20 + # wait to let the polling thread update the attrs value + time.sleep(3) + assert tango_context.device.onCmdDurationExpected == 20 + assert tango_context.device.offCmdDurationExpected == 20 + assert tango_context.device.standbyCmdDurationExpected == 20 + + -- GitLab From 877a3a579d09e178c5c7400e1cdebda70c89f2bd Mon Sep 17 00:00:00 2001 From: softir Date: Fri, 3 Apr 2020 16:50:27 +0200 Subject: [PATCH 06/17] AT5-370: added extra--url to install csp-lmc-common package and its dependencies. --- docker-requirements.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docker-requirements.txt b/docker-requirements.txt index 040cecb..92273ec 100644 --- a/docker-requirements.txt +++ b/docker-requirements.txt @@ -1,3 +1,4 @@ +--extra-index-url https://nexus.engageska-portugal.pt/repository/pypi/simple docutils markupsafe pygments @@ -13,4 +14,5 @@ sphinx-autobuild sphinx-rtd-theme sphinxcontrib-websupport pipdeptree -pylint_junit \ No newline at end of file +pylint_junit +csp-lmc-common >= 0.5.3 -- GitLab From c7f3f17e1a765bc7d4595aaa73c957dbd35ffa90 Mon Sep 17 00:00:00 2001 From: softir Date: Fri, 3 Apr 2020 17:58:25 +0200 Subject: [PATCH 07/17] AT5-370: move to docker directory before executing 'make lint' --- .gitlab-ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a39700f..66d1209 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -56,11 +56,12 @@ list_dependencies: - public linting: - image: nexus.engageska-portugal.pt/ska-docker/ska-python-buildenv:latest + image: nexus.engageska-portugal.pt/ska-docker/csp-lmc-subelement:latest tags: - docker-executor stage: linting script: + - cd docker - make lint when: always artifacts: @@ -98,4 +99,4 @@ create ci metrics: # Gitlab CI badges creation: END artifacts: paths: - - ./build \ No newline at end of file + - ./build -- GitLab From 6d602cb8aaef70ec7f27a640658d16991cad45eb Mon Sep 17 00:00:00 2001 From: softir Date: Fri, 3 Apr 2020 18:10:46 +0200 Subject: [PATCH 08/17] AT5-370: small changes to pass code linting. --- cspse/lmc/__init__.py | 3 +-- cspse/lmc/decorators.py | 2 +- docker/test-harness/Makefile | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/cspse/lmc/__init__.py b/cspse/lmc/__init__.py index 0fb30f2..1daa8af 100644 --- a/cspse/lmc/__init__.py +++ b/cspse/lmc/__init__.py @@ -1,6 +1,5 @@ __all__ = ( - "CspSubElementMaster", - "CspSubElementSubarray" + "CspSubElementMaster" ) from .subelement_master import CspSubElementMaster diff --git a/cspse/lmc/decorators.py b/cspse/lmc/decorators.py index 1fe7555..4436440 100644 --- a/cspse/lmc/decorators.py +++ b/cspse/lmc/decorators.py @@ -91,7 +91,7 @@ class IsCommandAllowed(object): cmd_to_exec = f.__name__ # the command input argument input_arg = args[1] - device_list = input_arg + #device_list = input_arg # Note: device list is a reference to args[1]: changing # device_list content, args[1] changes accordingly! num_of_devices = len(input_arg) diff --git a/docker/test-harness/Makefile b/docker/test-harness/Makefile index f951fe0..3e47977 100644 --- a/docker/test-harness/Makefile +++ b/docker/test-harness/Makefile @@ -24,7 +24,7 @@ test: lint: pip3 install pylint2junit; \ mkdir -p /build/reports; \ - cd /app && pylint --output-format=parseable csp_lmc_common | tee /build/csp-lmc-subelement-code-analysis.stdout; \ + cd /app && pylint --output-format=parseable cspse/lmc | tee /build/csp-lmc-subelement-code-analysis.stdout; \ cd /app && pylint --output-format=pylint2junit.JunitReporter cspse/lmc > /build/reports/csp-lmc-subelement-linting.xml; .PHONY: all test lint -- GitLab From e686be4033dff2816ad3d9e823b63b82984d7075 Mon Sep 17 00:00:00 2001 From: softir Date: Mon, 6 Apr 2020 09:09:43 +0200 Subject: [PATCH 09/17] AT5-370: problems with liniting stage. Stuck in waiting for a runner. --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 66d1209..bb3120e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -56,7 +56,7 @@ list_dependencies: - public linting: - image: nexus.engageska-portugal.pt/ska-docker/csp-lmc-subelement:latest + image: nexus.engageska-portugal.pt/ska-docker/ska-python-buildenv:latest tags: - docker-executor stage: linting -- GitLab From febf6d4c2be3d7c3249954271bb588a89b942a2a Mon Sep 17 00:00:00 2001 From: softir Date: Mon, 6 Apr 2020 09:22:13 +0200 Subject: [PATCH 10/17] AT5-370: project Makefile is in docker folder. --- Makefile | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index 462303c..0000000 --- a/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -# Use bash shell with pipefail option enabled so that the return status of a -# piped command is the value of the last (rightmost) commnand to exit with a -# non-zero status. This lets us pipe output into tee but still exit on test -# failures. -SHELL = /bin/bash -.SHELLFLAGS = -o pipefail -c - -all: test lint - -# The following steps copy across useful output to this volume which can -# then be extracted to form the CI summary for the test procedure. -test: - - python setup.py test | tee ./build/setup_py_test.stdout; \ - mv coverage.xml ./build/reports/code-coverage.xml; - -# The following steps copy across useful output to this volume which can -# then be extracted to form the CI summary for the test procedure. -lint: - - # FIXME pylint needs to run twice since there is no way go gather the text and junit xml output at the same time - pip3 install pylint2junit; \ - pylint --output-format=parseable ska_python_skeleton | tee ./build/code_analysis.stdout; \ - pylint --output-format=pylint2junit.JunitReporter ska_python_skeleton > ./build/reports/linting.xml; - - -.PHONY: all test lint -- GitLab From 7a3b70bb078e30b706221a7ed54ce62323f10ba5 Mon Sep 17 00:00:00 2001 From: Carlo Baffa Date: Mon, 6 Apr 2020 09:23:58 +0200 Subject: [PATCH 11/17] Deleted the inherited and unnecessary Makefile. Some comments. --- Makefile | 27 --------------------------- cspse/lmc/release.py | 2 +- cspse/lmc/subelement_master.py | 8 +++++++- 3 files changed, 8 insertions(+), 29 deletions(-) delete mode 100644 Makefile diff --git a/Makefile b/Makefile deleted file mode 100644 index 462303c..0000000 --- a/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -# Use bash shell with pipefail option enabled so that the return status of a -# piped command is the value of the last (rightmost) commnand to exit with a -# non-zero status. This lets us pipe output into tee but still exit on test -# failures. -SHELL = /bin/bash -.SHELLFLAGS = -o pipefail -c - -all: test lint - -# The following steps copy across useful output to this volume which can -# then be extracted to form the CI summary for the test procedure. -test: - - python setup.py test | tee ./build/setup_py_test.stdout; \ - mv coverage.xml ./build/reports/code-coverage.xml; - -# The following steps copy across useful output to this volume which can -# then be extracted to form the CI summary for the test procedure. -lint: - - # FIXME pylint needs to run twice since there is no way go gather the text and junit xml output at the same time - pip3 install pylint2junit; \ - pylint --output-format=parseable ska_python_skeleton | tee ./build/code_analysis.stdout; \ - pylint --output-format=pylint2junit.JunitReporter ska_python_skeleton > ./build/reports/linting.xml; - - -.PHONY: all test lint diff --git a/cspse/lmc/release.py b/cspse/lmc/release.py index 4e495d0..9e0117b 100755 --- a/cspse/lmc/release.py +++ b/cspse/lmc/release.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# This file is part of the CentralNode project +# This file is part of the CspSubElementMaster project # # # diff --git a/cspse/lmc/subelement_master.py b/cspse/lmc/subelement_master.py index f20a0c0..8b1493e 100644 --- a/cspse/lmc/subelement_master.py +++ b/cspse/lmc/subelement_master.py @@ -241,7 +241,6 @@ class CspSubElementMaster(SKAMaster): SKAMaster.init_device(self) self.set_state(tango.DevState.INIT) # PROTECTED REGION ID(CspSubElementMaster.init_device) ENABLED START # - # PROTECTED REGION ID(CspSubElementMaster.init_device) ENABLED START # # _cmd_execution_state: implement the execution state of a long-running # command for the whole CSP. Setting this attribute prevent the execution # of the same command while it is already running. @@ -512,6 +511,9 @@ class CspSubElementMaster(SKAMaster): The command is executed if the *AdminMode* is ONLINE or *MAINTENANCE*. If the AdminMode is *OFFLINE*, *NOT-FITTED* or *RESERVED*, the method throws an exception. + The CSP sub-element components can be organized as tango-groups or controlled + by some tango device drivers which actas as 'cache'. We call these devices + 'racks', even if they can contro a different phisical arrangement. :param argin: 'DevVarStringArray' The list of sub-element components FQDNs to switch-on or an empty list to switch-on the whole @@ -542,6 +544,10 @@ class CspSubElementMaster(SKAMaster): Switch-off the CSP sub-element components specified by the input argument. If no argument is specified, the command is issued to all the CSP sub-element components. + The CSP sub-element components can be organized as tango-groups or controlled + by some tango device drivers which actas as 'cache'. We call these devices + 'racks', even if they can contro a different phisical arrangement. + :param argin: 'DevVarStringArray' If the array length is 0, the command applies to the whole -- GitLab From 7bad8421095bfdf41f9932fa8bdc69a4a0489cd7 Mon Sep 17 00:00:00 2001 From: softir Date: Mon, 6 Apr 2020 09:32:44 +0200 Subject: [PATCH 12/17] AT5-370: change image to run linting. --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bb3120e..bf331a4 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -56,7 +56,7 @@ list_dependencies: - public linting: - image: nexus.engageska-portugal.pt/ska-docker/ska-python-buildenv:latest + image: nexus.engageska-portugal.pt/ska-docker/tango-builder:latest tags: - docker-executor stage: linting -- GitLab From 8ad83c8baea96c8c7f5ab67eabc8f304dec2ef20 Mon Sep 17 00:00:00 2001 From: softir Date: Mon, 6 Apr 2020 09:50:26 +0200 Subject: [PATCH 13/17] AT5-370: call pylint from pipeline (no makefile) --- .gitlab-ci.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bf331a4..4bbc1e0 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -56,13 +56,11 @@ list_dependencies: - public linting: - image: nexus.engageska-portugal.pt/ska-docker/tango-builder:latest - tags: - - docker-executor stage: linting script: - - cd docker - - make lint + - pip3 install pylint2junit + - pylint --output-format=parseable cspse | tee ./build/code_analysis.stdout + - pylint --output-format=pylint2junit.JunitReporter cspse > ./build/reports/linting.xml; when: always artifacts: paths: -- GitLab From a9803bb84b7a37f2bf2dcd98819eb6d64145c315 Mon Sep 17 00:00:00 2001 From: Carlo Baffa Date: Mon, 6 Apr 2020 12:39:24 +0200 Subject: [PATCH 14/17] Some work on Readme.md --- README.md | 120 +++++++++++++++++++++++++++--------------------------- 1 file changed, 59 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index 94e8728..3a0acee 100644 --- a/README.md +++ b/README.md @@ -1,78 +1,76 @@ -SKA Python Skeleton Project -=========================== +SKA CSP-LMC-SUBELEMENT Abstract Class +===================================== [![Documentation Status](https://readthedocs.org/projects/ska-python-skeleton/badge/?version=latest)](https://developer.skatelescope.org/projects/skeleton/en/latest/?badge=latest) -Briefly describe your project here +## Table of contents +* [Description](#description) +* [Getting started](#getting-started) +* [Repository](#repository) +* [Prerequisities](#prerequisities) +* [Running tests](#running-tests) +* [Known bugs](#known-bugs) +* [Troubleshooting](#troubleshooting) +* [License](#license) -Requirements ------------- +## Description -The system used for development needs to have Python 3 and `pip` installed. +This project contains the `CSP.LMC.SUBELEMENT` prototype. It includes a +single class: -Install -------- +* the `CspSubElementMaster` device: based on the `CspMaster` class. The +`CspSubElementMaster` represents a primary point of contact for CSP +SubElement Monitor and Control. It implements CSP SubElement state and +mode indicators and a limited set of housekeeping commands. +It is intended to connect to the various subcomponent of SubElement. This +can be accomplished directly or by means of a _caching_ device, called +`Rack`. Of course it is a device collector and can or cannot correspond to a +physical rack. -**Always** use a virtual environment. [Pipenv](https://pipenv.readthedocs.io/en/latest/) is now Python's officially -recommended method, but we are not using it for installing requirements when building on the CI Pipeline. You are encouraged to use your preferred environment isolation (i.e. `pip`, `conda` or `pipenv` while developing locally. -For working with `Pipenv`, follow these steps at the project root: +## Getting started -First, ensure that `~/.local/bin` is in your `PATH` with: -```bash -> echo $PATH -``` +The project can be found in the SKA gitlab repository. + +To get a local copy of the project: -In case `~/.local/bin` is not part of your `PATH` variable, under Linux add it with: ```bash -> export PATH=~/.local/bin:$PATH +git clone https://gitlab.com/ska-telescope/csp-lmc-subelement.git ``` -or the equivalent in your particular OS. +## Prerequisities + +* A TANGO development environment properly configured, as described in [SKA developer portal](https://developer.skatelescope.org/en/latest/tools/tango-devenv-setup.html) + +* [SKA Base classes](https://gitlab.com/ska-telescope/lmc-base-classes) + + +## Repository organization + +The `CSP.LMC.SUBELEMENT` repository is organized in a single code tree. The +hierarchy contains: + +* _cspse_: contains the specific project TANGO Device Class files +* _pogo_: contains the POGO files of the TANGO Device Classes of the project +* _docker_: contains the `docker`, `docker-compose` and `dsconfig` configuration files as well as the Makefile to generate the docker image and run the tests. +* _tests_: contains the test -Then proceed to install pipenv and the required environment packages: +## Running tests + +To run the internal test go to `tests` directory and execute: ```bash -> pip install pipenv # if you don't have pipenv already installed on your system -> pipenv install -> pipenv shell +make test ``` -You will now be inside a pipenv shell with your virtual environment ready. - -Use `exit` to exit the pipenv environment. - - -Testing -------- - -* Put tests into the `tests` folder -* Use [PyTest](https://pytest.org) as the testing framework - - Reference: [PyTest introduction](http://pythontesting.net/framework/pytest/pytest-introduction/) -* Run tests with `python setup.py test` - - Configure PyTest in `setup.py` and `setup.cfg` -* Running the test creates the `htmlcov` folder - - Inside this folder a rundown of the issues found will be accessible using the `index.html` file -* All the tests should pass before merging the code - - Code analysis - ------------- - * Use [Pylint](https://www.pylint.org) as the code analysis framework - * By default it uses the [PEP8 style guide](https://www.python.org/dev/peps/pep-0008/) - * Use the provided `code-analysis.sh` script in order to run the code analysis in the `module` and `tests` - * Code analysis should be run by calling `pylint ska_python_skeleton`. All pertaining options reside under the `.pylintrc` file. - * Code analysis should only raise document related warnings (i.e. `#FIXME` comments) before merging the code - -Writing documentation - -------------------- - * The documentation generator for this project is derived from SKA's [SKA Developer Portal repository](https://github.com/ska-telescope/developer.skatelescope.org) - * The documentation can be edited under `./docs/src` - * If you want to include only your README.md file, create a symbolic link inside the `./docs/src` directory if the existing one does not work: - ```bash -$ cd docs/src -$ ln -s ../../README.md README.md -``` - * In order to build the documentation for this specific project, execute the following under `./docs`: - ```bash -$ make html -``` -* The documentation can then be consulted by opening the file `./docs/build/html/index.html` +## Known bugs + +_Still none_ + +## Troubleshooting + +TBD + +## License +See the LICENSE file for details. + + -- GitLab From 551ca77a536901a3d5cfa6136b66ddf628969183 Mon Sep 17 00:00:00 2001 From: softir Date: Tue, 7 Apr 2020 10:11:11 +0200 Subject: [PATCH 15/17] AT5-370: first attempt to generate CSP.LMC SubElement Classes documentation. --- docs/src/conf.py | 17 ++++++++++++----- docs/src/package/guide.rst | 32 ++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/docs/src/conf.py b/docs/src/conf.py index 8ee1cc5..fae9193 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -17,9 +17,16 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # +autodoc_mock_imports = ['PyTango', 'tango', 'tango.server','run', 'DeviceMeta', 'command', + 'future', 'future.utils', 'logging', 'logging.handlers', 'ska', + 'ska.base', 'SKAMaster', 'SKASubarray','numpy', + 'csp_lmc_common' + ] +autodoc_member_order = 'bysource' + import os import sys -sys.path.insert(0, os.path.abspath('../..')) +sys.path.insert(0, os.path.abspath('../../')) import sphinx_rtd_theme def setup(app): @@ -45,7 +52,7 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode', 'sphinx.ext.githubpages', - 'recommonmark'] + 'recommonmark'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -60,9 +67,9 @@ source_suffix = ['.rst', '.md'] master_doc = 'index' # General information about the project. -project = 'developer.skatelescope.org' -copyright = '2018, SKA Organization' -author = 'Marco Bartolini' +project = 'Csp:LMC Subelement Classes' +copyright = '2020, INAF-SKA Organization' +author = 'E.Giani' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/docs/src/package/guide.rst b/docs/src/package/guide.rst index 9b3c93e..f5bf107 100644 --- a/docs/src/package/guide.rst +++ b/docs/src/package/guide.rst @@ -2,18 +2,13 @@ .. _package-guide: .. todo:: - - Insert todo's here + - write documentation for private and protected attributes and methods of + the CSP.LMC Subelement classes. -************************** -Package-name documentation -************************** +***************************************** +CSP.LMC Subelement Classes documentation +***************************************** -This section describes requirements and guidelines. - -Subtitle -======== - -Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. .. Automatic API Documentation section. Generating the API from the docstrings. Modify / change the directory structure as you like @@ -22,11 +17,20 @@ Public API Documentation Functions --------- -.. automodule:: ska_python_skeleton.ska_python_skeleton +.. automodule:: cspse.lmc.subelement_master + :members: + +CspSubElementMaster Class +------------------------- +.. autoclass:: cspse.lmc.subelement_master.CspSubElementMaster + :noindex: :members: -Classes -------- -.. autoclass:: ska_python_skeleton.ska_python_skeleton.SKA +CspSubElementSubarray Class +--------------------------- +.. autoclass:: cspse.lmc.subelement_master.CspSubElementMaster :noindex: :members: + +CspSubElementSubarray Class +--------------------------- -- GitLab From d0f83e77a788864ecff0b38f66a5b521b9c21dd7 Mon Sep 17 00:00:00 2001 From: Elisabetta Giani Date: Tue, 7 Apr 2020 05:29:46 -0400 Subject: [PATCH 16/17] AT5-370: Updated documentation inside subelement_master.py. Changes to docs configuraiton files. --- cspse/lmc/subelement_master.py | 59 +++++++++++++++++----------------- docs/src/conf.py | 20 ++++++------ docs/src/index.rst | 2 +- docs/src/package/guide.rst | 32 ++++++------------ 4 files changed, 51 insertions(+), 62 deletions(-) diff --git a/cspse/lmc/subelement_master.py b/cspse/lmc/subelement_master.py index 7958c62..fc4454c 100644 --- a/cspse/lmc/subelement_master.py +++ b/cspse/lmc/subelement_master.py @@ -108,7 +108,9 @@ class CspSubElementMaster(SKAMaster): dtype=AdminMode, access=AttrWriteType.READ_WRITE, memorized=True, - doc="The admin mode reported for this device. It may interpret the current device condition \nand condition of all managed devices to set this. Most possibly an aggregate attribute.", + doc=("The admin mode reported for this device. It may interpret the current" + " device condition and condition of all managed devices to set this." + " Most possibly an aggregate attribute."), ) onCommandProgress = attribute( @@ -117,7 +119,9 @@ class CspSubElementMaster(SKAMaster): abs_change=10, max_value=100, min_value=0, - doc="Percentage progress implemented for commands that result in state/mode transitions for a large \nnumber of components and/or are executed in stages (e.g power up, power down)", + doc=("Percentage progress implemented for commands that result in state/mode" + " transitions for a large number of components and/or are executed in " + "stages (e.g power up, power down)"), ) offCommandProgress = attribute( @@ -126,7 +130,9 @@ class CspSubElementMaster(SKAMaster): abs_change=10, max_value=100, min_value=0, - doc="Percentage progress implemented for commands that result in state/mode transitions for a large \nnumber of components and/or are executed in stages (e.g power up, power down)", + doc=("Percentage progress implemented for commands that result in state/mode transitions" + " for a large number of components and/or are executed in stages" + " (e.g power up, power down)"), ) standbyCommandProgress = attribute( @@ -135,7 +141,9 @@ class CspSubElementMaster(SKAMaster): abs_change=10, max_value=100, min_value=0, - doc="Percentage progress implemented for commands that result in state/mode transitions for a large \nnumber of components and/or are executed in stages (e.g power up, power down)", + doc=("Percentage progress implemented for commands that result in state/mode" + " transitions for a large number of components and/or are executed in" + " stages (e.g power up, power down)"), ) onCmdDurationExpected = attribute( @@ -513,15 +521,11 @@ class CspSubElementMaster(SKAMaster): by some tango device drivers which actas as 'cache'. We call these devices 'racks', even if they can contro a different phisical arrangement. - :param argin: 'DevVarStringArray' - The list of sub-element components FQDNs to switch-on or an empty list to switch-on the whole - CSP Sub-element. - - If the array length is 0, the command applies to the whole CSP Sub-Element. If the - array length is > 1, each array element specifies the FQDN of the - CSP SubElement component to switch ON. - - :return:None + :param argin: The list of sub-element components FQDNs: if the array length is 0 (empty input \ + list), the command applies to the whole CSP Sub-Element. If the array length is > 1, \ + each array element specifies the FQDN of the CSP SubElement component to switch ON. + :type: 'DevVarStringArray' + :return: None """ pass # PROTECTED REGION END # // CspSubElementMaster.On @@ -547,13 +551,12 @@ class CspSubElementMaster(SKAMaster): 'racks', even if they can contro a different phisical arrangement. - :param argin: 'DevVarStringArray' - If the array length is 0, the command applies to the whole - CSP Sub-element. - If the array length is > 1, each array element specifies the FQDN of the - CSP SubElement component to switch OFF. - - :return:None + :param argin: The list of sub-element components FQDNs: if the array length is 0 (no list \ + specified), the command applies to the whole CSP sub-element. If the array length \ + is > 1, each array element specifies the FQDN of a CSP SubElement component to switch \ + off. + :type: 'DevVarStringArray' + :return: None """ pass # PROTECTED REGION END # // CspSubElementMaster.Off @@ -574,13 +577,12 @@ class CspSubElementMaster(SKAMaster): Transit the CSP Sub-element or one or more CSP SubElement components from ON/OFF to STANDBY. - :param argin: 'DevVarStringArray' - If the array length is 0, the command applies to the whole - CSP sub-element. - If the array length is > 1, each array element specifies the FQDN of the - CSP SubElement icomponent to put in STANDBY mode. - - :return:None + :param argin: The list of sub-element components FQDNs: if the array length is 0 (no list \ + specified), the command applies to the whole CSP sub-element. If the array length \ + is > 1, each array element specifies the FQDN of a CSP SubElement component to put \ + in STANDBY mode. + :type: 'DevVarStringArray' + :return: None """ pass # PROTECTED REGION END # // CspSubElementMaster.Standby @@ -591,8 +593,7 @@ class CspSubElementMaster(SKAMaster): def Upgrade(self): # PROTECTED REGION ID(CspSubElementMaster.Upgrade) ENABLED START # """ - - :return:None + :return: None """ pass # PROTECTED REGION END # // CspSubElementMaster.Upgrade diff --git a/docs/src/conf.py b/docs/src/conf.py index fae9193..0071d7d 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -17,9 +17,9 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # -autodoc_mock_imports = ['PyTango', 'tango', 'tango.server','run', 'DeviceMeta', 'command', +autodoc_mock_imports = ['PyTango', 'tango', 'tango.server','run', 'command', 'future', 'future.utils', 'logging', 'logging.handlers', 'ska', - 'ska.base', 'SKAMaster', 'SKASubarray','numpy', + 'ska.base', 'ska.base.control_model', 'SKAMaster', 'SKASubarray','numpy', 'csp_lmc_common' ] autodoc_member_order = 'bysource' @@ -28,7 +28,6 @@ import os import sys sys.path.insert(0, os.path.abspath('../../')) import sphinx_rtd_theme - def setup(app): app.add_stylesheet('css/custom.css') app.add_javascript('js/github.js') @@ -52,7 +51,8 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode', 'sphinx.ext.githubpages', - 'recommonmark'] + 'recommonmark' + ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -69,7 +69,7 @@ master_doc = 'index' # General information about the project. project = 'Csp:LMC Subelement Classes' copyright = '2020, INAF-SKA Organization' -author = 'E.Giani' +author = 'C.Baffa, E.Giani' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -179,8 +179,8 @@ latex_elements = { # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'developerskatelescopeorg.tex', 'developer.skatelescope.org Documentation', - 'Marco Bartolini', 'manual'), + (master_doc, 'CspLMCSubElement.tex', 'CSP.LMC Subelement TANGO Classes Documentation', + 'SKA Organization', 'manual'), ] @@ -189,7 +189,7 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - (master_doc, 'developerskatelescopeorg', 'developer.skatelescope.org Documentation', + (master_doc, 'csplmc-subelement', 'CSP.LMC Subelement TANGO Classes Documentation', [author], 1) ] @@ -200,8 +200,8 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'developerskatelescopeorg', 'developer.skatelescope.org Documentation', - author, 'developerskatelescopeorg', 'One line description of project.', + (master_doc, 'CSP.LMC-SubElement', 'CSP.LMC Subelement TANGO Classes Documentation', + author, 'CSP.LMC-SubElement', 'One line description of project.', 'Miscellaneous'), ] diff --git a/docs/src/index.rst b/docs/src/index.rst index 3052688..245a103 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -30,7 +30,7 @@ .. toctree:: :maxdepth: 2 - :caption: Package name + :caption: Csp.LMC SubElement TANGO Classes :hidden: package/guide diff --git a/docs/src/package/guide.rst b/docs/src/package/guide.rst index f5bf107..92df00e 100644 --- a/docs/src/package/guide.rst +++ b/docs/src/package/guide.rst @@ -5,32 +5,20 @@ - write documentation for private and protected attributes and methods of the CSP.LMC Subelement classes. -***************************************** -CSP.LMC Subelement Classes documentation -***************************************** +************************ +Public API documentation +************************ .. Automatic API Documentation section. Generating the API from the docstrings. Modify / change the directory structure as you like -Public API Documentation -```````````````````````` -Functions ---------- - +CspSubElementMaster TANGO Class +-------------------------------- .. automodule:: cspse.lmc.subelement_master :members: + :member-order: -CspSubElementMaster Class -------------------------- -.. autoclass:: cspse.lmc.subelement_master.CspSubElementMaster - :noindex: - :members: - -CspSubElementSubarray Class ---------------------------- -.. autoclass:: cspse.lmc.subelement_master.CspSubElementMaster - :noindex: - :members: - -CspSubElementSubarray Class ---------------------------- +CspSubElementSubarray TANGO Class +--------------------------------- +.. todo:: + - write documentation for CSP.LMC SubElementSubarray Class -- GitLab From 5698970bab3a684aaec0ee07d66fd426252a26d3 Mon Sep 17 00:00:00 2001 From: Carlo Baffa Date: Tue, 7 Apr 2020 15:25:35 +0200 Subject: [PATCH 17/17] Few additions on documentation --- docs/src/index.rst | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/src/index.rst b/docs/src/index.rst index 245a103..4b79b17 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -13,6 +13,10 @@ :caption: Home :hidden: +SKA CSP-LMC-SUBELEMENT Abstract Class +===================================== + +This project contains the `CSP.LMC.SUBELEMENT` abstract classes prototype. .. README ============================================================= @@ -20,7 +24,7 @@ .. toctree:: :maxdepth: 2 - :caption: Readme + :caption: Introduction ../../README @@ -36,9 +40,12 @@ package/guide -Project-name documentation HEADING -================================== +Detailed Abstract Class Documentation +===================================== + -These are all the packages, functions and scripts that form part of the project. +We report here the detailed descriptions of the component that form part of the project. +This project includes few classes: the `CspSubElementMaster`, the `CspSubElementSubarray` and +the `Rack` device drivers. - :doc:`package/guide` -- GitLab