From 6cb678194ddad16cd59622ae2ac88e12e5cb9ca0 Mon Sep 17 00:00:00 2001 From: Chsudeepta Date: Mon, 8 Sep 2025 15:46:53 +0100 Subject: [PATCH 01/22] Ticket8780: Added logic to save alarm configs on blocks --- BlockServer/config/block.py | 32 ++++++++++++++ BlockServer/config/xml_converter.py | 42 ++++++++++++++++++- BlockServer/core/constants.py | 8 ++++ .../test_modules/test_configuration_xml.py | 13 ++++++ 4 files changed, 94 insertions(+), 1 deletion(-) diff --git a/BlockServer/config/block.py b/BlockServer/config/block.py index d138ec69..82984cee 100644 --- a/BlockServer/config/block.py +++ b/BlockServer/config/block.py @@ -33,6 +33,13 @@ class Block: log_periodic (bool): Whether the block is sampled periodically in the archiver log_rate (float): Time between archive samples (in seconds) log_deadband (float): Deadband for the block to be archived + alarmenabled (bool): Whether the alarm should be enabled + alarmlatched (bool): Whether the alarm should be latched + alarmlowlimit (float): The low limit for alarm + alarmhighlimit (float): The high limit for alarm + alarmdelay (float): The delay for trigerring alarm + alarmguidance (string): The guidance for the alarm + """ def __init__( @@ -51,6 +58,12 @@ def __init__( log_deadband: float = 0, set_block: bool = False, set_block_val: str = None, + alarmenabled: bool = False, + alarmlatched: bool = False, + alarmlowlimit: float = None, + alarmhighlimit: float = None, + alarmdelay: float = None, + alarmguidance: str = None, ): """Constructor. @@ -69,6 +82,12 @@ def __init__( log_deadband: Deadband for the block to be archived set_block: whether the block should be set upon config change set_block_val: what the block should be set to upon config change + alarmenabled (bool): Whether the alarm should be enabled + alarmlatched (bool): Whether the alarm should be latched + alarmlowlimit (float): The low limit for alarm + alarmhighlimit (float): The high limit for alarm + alarmdelay (float): The delay for trigerring alarm + alarmguidance (string): The guidance for the alarm """ self.name = name self.pv = pv @@ -84,6 +103,13 @@ def __init__( self.log_deadband = log_deadband self.set_block = set_block self.set_block_val = set_block_val + self.alarmenabled = alarmenabled + self.alarmlatched = alarmlatched + self.alarmlowlimit = alarmlowlimit + self.alarmhighlimit = alarmhighlimit + self.alarmdelay = alarmdelay + self.alarmguidance = alarmguidance + def _get_pv(self) -> str: pv_name = self.pv @@ -130,4 +156,10 @@ def to_dict(self) -> Dict[str, Union[str, float, bool]]: "suspend_on_invalid": self.rc_suspend_on_invalid, "set_block": self.set_block, "set_block_val": self.set_block_val, + "alarmenabled": self.alarmenabled, + "alarmlatched": self.alarmlatched, + "alarmlowlimit": self.alarmlowlimit, + "alarmhighlimit": self.alarmhighlimit, + "alarmdelay": self.alarmdelay, + "alarmguidance": self.alarmguidance, } diff --git a/BlockServer/config/xml_converter.py b/BlockServer/config/xml_converter.py index feb329a9..854697b1 100644 --- a/BlockServer/config/xml_converter.py +++ b/BlockServer/config/xml_converter.py @@ -236,7 +236,24 @@ def _block_to_xml(root_xml: ElementTree.Element, block: Block, macros: Dict): set_block_val = ElementTree.SubElement(block_xml, TAG_SET_BLOCK_VAL) set_block_val.text = str(block.set_block_val) - + + # Alarm Config + alarmenabled = ElementTree.SubElement(block_xml, TAG_ALARM_ENABLED) + alarmenabled.text = str(block.alarmenabled) + alarmlatched = ElementTree.SubElement(block_xml, TAG_ALARM_LATCHED) + alarmlatched.text = str(block.alarmlatched) + if block.alarmlowlimit is not None: + alarmlowlimit = ElementTree.SubElement(block_xml, TAG_ALARM_LOW) + alarmlowlimit.text = str(block.alarmlowlimit) + if block.alarmhighlimit is not None: + alarmhighlimit = ElementTree.SubElement(block_xml, TAG_ALARM_HIGH) + alarmhighlimit.text = str(block.alarmhighlimit) + if block.alarmdelay is not None: + alarmdelay = ElementTree.SubElement(block_xml, TAG_ALARM_DELAY) + alarmdelay.text = str(block.alarmdelay) + alarmguidance = ElementTree.SubElement(block_xml, TAG_ALARM_GUIDANCE) + alarmguidance.text = block.alarmguidance + @staticmethod def _group_to_xml(root_xml: ElementTree, group: Group): """Generates the XML for a group""" @@ -366,6 +383,29 @@ def blocks_from_xml(root_xml: ElementTree.Element, blocks: OrderedDict, groups: ) if set_block_val is not None: blocks[name.lower()].set_block_val = set_block_val.text + + # Alarm Config + alarmenabled = ConfigurationXmlConverter._find_single_node(b, NS_TAG_BLOCK, TAG_ALARM_ENABLED) + if alarmenabled is not None: + blocks[name.lower()].alarmenabled = alarmenabled.text == "True" + alarmlatched = ConfigurationXmlConverter._find_single_node(b, NS_TAG_BLOCK, TAG_ALARM_LATCHED) + if alarmlatched is not None: + blocks[name.lower()].alarmlatched = alarmlatched.text == "True" + alarmlowlimit = ConfigurationXmlConverter._find_single_node(b, NS_TAG_BLOCK, TAG_ALARM_LOW) + if alarmlowlimit is not None: + blocks[name.lower()].alarmlowlimit = float(alarmlowlimit.text) + alarmhighlimit = ConfigurationXmlConverter._find_single_node(b, NS_TAG_BLOCK, TAG_ALARM_HIGH) + if alarmhighlimit is not None: + blocks[name.lower()].alarmhighlimit = float(alarmhighlimit.text) + alarmdelay = ConfigurationXmlConverter._find_single_node(b, NS_TAG_BLOCK, TAG_ALARM_DELAY) + if alarmdelay is not None: + blocks[name.lower()].alarmdelay = float(alarmdelay.text) + alarmguidance = ConfigurationXmlConverter._find_single_node(b, NS_TAG_BLOCK, TAG_ALARM_GUIDANCE) + if alarmguidance is not None: + blocks[name.lower()].alarmguidance = alarmguidance.text + + + @staticmethod def groups_from_xml(root_xml: ElementTree.Element, groups: OrderedDict, blocks: OrderedDict): diff --git a/BlockServer/core/constants.py b/BlockServer/core/constants.py index 3620c54d..14824f61 100644 --- a/BlockServer/core/constants.py +++ b/BlockServer/core/constants.py @@ -81,3 +81,11 @@ FILENAME_BANNER = "banner.xml" SCHEMA_FOR = [FILENAME_BLOCKS, FILENAME_GROUPS, FILENAME_IOCS, FILENAME_COMPONENTS, FILENAME_META] + +# Alarm element nodes +TAG_ALARM_ENABLED = "alarm_enabled" +TAG_ALARM_LATCHED = "alarm_latched" +TAG_ALARM_LOW = "alarm_lowlimit" +TAG_ALARM_HIGH = "alarm_highlimit" +TAG_ALARM_DELAY = "alarm_delay" +TAG_ALARM_GUIDANCE = "alarm_guidance" diff --git a/BlockServer/test_modules/test_configuration_xml.py b/BlockServer/test_modules/test_configuration_xml.py index 8f8bda98..098da4d7 100644 --- a/BlockServer/test_modules/test_configuration_xml.py +++ b/BlockServer/test_modules/test_configuration_xml.py @@ -44,6 +44,9 @@ 0 False None + False + False + TESTBLOCK2 @@ -59,6 +62,9 @@ 0 False None + False + False + TESTBLOCK3 @@ -74,6 +80,9 @@ 0 False None + False + False + TESTBLOCK4 @@ -89,6 +98,9 @@ 0 False None + False + False + """ @@ -243,6 +255,7 @@ def test_blocks_to_xml_converts_correctly(self): blocks_xml = strip_out_whitespace(blocks_xml) # Assert + print(blocks_xml) self.assertEqual(blocks_xml, BLOCKS_XML) def test_groups_to_xml_converts_correctly(self): From 30dec666370b4a4850ef1e00437405e58919c17d Mon Sep 17 00:00:00 2001 From: Chsudeepta Date: Fri, 12 Sep 2025 14:55:24 +0100 Subject: [PATCH 02/22] Removed alarm limit configuration logic --- BlockServer/config/block.py | 10 ---------- BlockServer/config/xml_converter.py | 14 -------------- BlockServer/core/constants.py | 2 -- 3 files changed, 26 deletions(-) diff --git a/BlockServer/config/block.py b/BlockServer/config/block.py index 82984cee..d6d33324 100644 --- a/BlockServer/config/block.py +++ b/BlockServer/config/block.py @@ -35,8 +35,6 @@ class Block: log_deadband (float): Deadband for the block to be archived alarmenabled (bool): Whether the alarm should be enabled alarmlatched (bool): Whether the alarm should be latched - alarmlowlimit (float): The low limit for alarm - alarmhighlimit (float): The high limit for alarm alarmdelay (float): The delay for trigerring alarm alarmguidance (string): The guidance for the alarm @@ -60,8 +58,6 @@ def __init__( set_block_val: str = None, alarmenabled: bool = False, alarmlatched: bool = False, - alarmlowlimit: float = None, - alarmhighlimit: float = None, alarmdelay: float = None, alarmguidance: str = None, ): @@ -84,8 +80,6 @@ def __init__( set_block_val: what the block should be set to upon config change alarmenabled (bool): Whether the alarm should be enabled alarmlatched (bool): Whether the alarm should be latched - alarmlowlimit (float): The low limit for alarm - alarmhighlimit (float): The high limit for alarm alarmdelay (float): The delay for trigerring alarm alarmguidance (string): The guidance for the alarm """ @@ -105,8 +99,6 @@ def __init__( self.set_block_val = set_block_val self.alarmenabled = alarmenabled self.alarmlatched = alarmlatched - self.alarmlowlimit = alarmlowlimit - self.alarmhighlimit = alarmhighlimit self.alarmdelay = alarmdelay self.alarmguidance = alarmguidance @@ -158,8 +150,6 @@ def to_dict(self) -> Dict[str, Union[str, float, bool]]: "set_block_val": self.set_block_val, "alarmenabled": self.alarmenabled, "alarmlatched": self.alarmlatched, - "alarmlowlimit": self.alarmlowlimit, - "alarmhighlimit": self.alarmhighlimit, "alarmdelay": self.alarmdelay, "alarmguidance": self.alarmguidance, } diff --git a/BlockServer/config/xml_converter.py b/BlockServer/config/xml_converter.py index 854697b1..8f919909 100644 --- a/BlockServer/config/xml_converter.py +++ b/BlockServer/config/xml_converter.py @@ -242,12 +242,6 @@ def _block_to_xml(root_xml: ElementTree.Element, block: Block, macros: Dict): alarmenabled.text = str(block.alarmenabled) alarmlatched = ElementTree.SubElement(block_xml, TAG_ALARM_LATCHED) alarmlatched.text = str(block.alarmlatched) - if block.alarmlowlimit is not None: - alarmlowlimit = ElementTree.SubElement(block_xml, TAG_ALARM_LOW) - alarmlowlimit.text = str(block.alarmlowlimit) - if block.alarmhighlimit is not None: - alarmhighlimit = ElementTree.SubElement(block_xml, TAG_ALARM_HIGH) - alarmhighlimit.text = str(block.alarmhighlimit) if block.alarmdelay is not None: alarmdelay = ElementTree.SubElement(block_xml, TAG_ALARM_DELAY) alarmdelay.text = str(block.alarmdelay) @@ -391,20 +385,12 @@ def blocks_from_xml(root_xml: ElementTree.Element, blocks: OrderedDict, groups: alarmlatched = ConfigurationXmlConverter._find_single_node(b, NS_TAG_BLOCK, TAG_ALARM_LATCHED) if alarmlatched is not None: blocks[name.lower()].alarmlatched = alarmlatched.text == "True" - alarmlowlimit = ConfigurationXmlConverter._find_single_node(b, NS_TAG_BLOCK, TAG_ALARM_LOW) - if alarmlowlimit is not None: - blocks[name.lower()].alarmlowlimit = float(alarmlowlimit.text) - alarmhighlimit = ConfigurationXmlConverter._find_single_node(b, NS_TAG_BLOCK, TAG_ALARM_HIGH) - if alarmhighlimit is not None: - blocks[name.lower()].alarmhighlimit = float(alarmhighlimit.text) alarmdelay = ConfigurationXmlConverter._find_single_node(b, NS_TAG_BLOCK, TAG_ALARM_DELAY) if alarmdelay is not None: blocks[name.lower()].alarmdelay = float(alarmdelay.text) alarmguidance = ConfigurationXmlConverter._find_single_node(b, NS_TAG_BLOCK, TAG_ALARM_GUIDANCE) if alarmguidance is not None: blocks[name.lower()].alarmguidance = alarmguidance.text - - @staticmethod diff --git a/BlockServer/core/constants.py b/BlockServer/core/constants.py index 14824f61..0f7ece74 100644 --- a/BlockServer/core/constants.py +++ b/BlockServer/core/constants.py @@ -85,7 +85,5 @@ # Alarm element nodes TAG_ALARM_ENABLED = "alarm_enabled" TAG_ALARM_LATCHED = "alarm_latched" -TAG_ALARM_LOW = "alarm_lowlimit" -TAG_ALARM_HIGH = "alarm_highlimit" TAG_ALARM_DELAY = "alarm_delay" TAG_ALARM_GUIDANCE = "alarm_guidance" From 8bd59853109845d4259efa3e7a11efe91f2e167f Mon Sep 17 00:00:00 2001 From: Chsudeepta Date: Tue, 18 Nov 2025 13:58:17 +0000 Subject: [PATCH 03/22] Fixed some ruff comments --- BlockServer/test_modules/test_configuration_xml.py | 1 - 1 file changed, 1 deletion(-) diff --git a/BlockServer/test_modules/test_configuration_xml.py b/BlockServer/test_modules/test_configuration_xml.py index 098da4d7..e53e4a3a 100644 --- a/BlockServer/test_modules/test_configuration_xml.py +++ b/BlockServer/test_modules/test_configuration_xml.py @@ -255,7 +255,6 @@ def test_blocks_to_xml_converts_correctly(self): blocks_xml = strip_out_whitespace(blocks_xml) # Assert - print(blocks_xml) self.assertEqual(blocks_xml, BLOCKS_XML) def test_groups_to_xml_converts_correctly(self): From ca582ebbe65f5298fb24e48ec4d5d24c218b0727 Mon Sep 17 00:00:00 2001 From: Chsudeepta Date: Fri, 21 Nov 2025 13:48:54 +0000 Subject: [PATCH 04/22] some ruff stuff fixes --- BlockServer/config/block.py | 27 ++++++----- BlockServer/config/xml_converter.py | 75 ++++++++++++++++++----------- 2 files changed, 61 insertions(+), 41 deletions(-) diff --git a/BlockServer/config/block.py b/BlockServer/config/block.py index d6d33324..dc9d7b20 100644 --- a/BlockServer/config/block.py +++ b/BlockServer/config/block.py @@ -13,6 +13,7 @@ # along with this program; if not, you can obtain a copy from # https://www.eclipse.org/org/documents/epl-v10.php or # http://opensource.org/licenses/eclipse-1.0.php +# pyright: reportMissingImports=false from typing import Dict, Union from server_common.helpers import PVPREFIX_MACRO @@ -46,21 +47,21 @@ def __init__( pv: str, local: bool = True, visible: bool = True, - component: str = None, + component: str | None = None, runcontrol: bool = False, - lowlimit: float = None, - highlimit: float = None, + lowlimit: float | None = None, + highlimit: float | None = None, suspend_on_invalid: bool = False, log_periodic: bool = False, log_rate: float = 5, log_deadband: float = 0, set_block: bool = False, - set_block_val: str = None, + set_block_val: str | None = None, alarmenabled: bool = False, alarmlatched: bool = False, - alarmdelay: float = None, - alarmguidance: str = None, - ): + alarmdelay: float | None = None, + alarmguidance: str | None = None, + ) -> None: """Constructor. Args: @@ -102,7 +103,6 @@ def __init__( self.alarmdelay = alarmdelay self.alarmguidance = alarmguidance - def _get_pv(self) -> str: pv_name = self.pv # Check starts with as may have already been provided @@ -110,7 +110,7 @@ def _get_pv(self) -> str: pv_name = PVPREFIX_MACRO + self.pv return pv_name - def set_visibility(self, visible: bool): + def set_visibility(self, visible: bool) -> None: """Toggle the visibility of the block. Args: @@ -118,16 +118,17 @@ def set_visibility(self, visible: bool): """ self.visible = visible - def __str__(self): + def __str__(self) -> str: set_block_str = "" if self.set_block: set_block_str = f", SetBlockVal: {self.set_block_val}" return ( - f"Name: {self.name}, PV: {self.pv}, Local: {self.local}, Visible: {self.visible}, Component: {self.component}" - f", RCEnabled: {self.rc_enabled}, RCLow: {self.rc_lowlimit}, RCHigh: {self.rc_highlimit}{set_block_str}" + f"Name: {self.name}, PV: {self.pv}, Local: {self.local}, Visible: {self.visible}, " + f"Component: {self.component}, RCEnabled: {self.rc_enabled}, RCLow: {self.rc_lowlimit}" + f", RCHigh: {self.rc_highlimit}{set_block_str}" ) - def to_dict(self) -> Dict[str, Union[str, float, bool]]: + def to_dict(self) -> Dict[str, Union[str, float, bool, None]]: """Puts the block's details into a dictionary. Returns: diff --git a/BlockServer/config/xml_converter.py b/BlockServer/config/xml_converter.py index 8f919909..bf36db2a 100644 --- a/BlockServer/config/xml_converter.py +++ b/BlockServer/config/xml_converter.py @@ -13,6 +13,9 @@ # along with this program; if not, you can obtain a copy from # https://www.eclipse.org/org/documents/epl-v10.php or # http://opensource.org/licenses/eclipse-1.0.php +# ruff: noqa: F403, F405, N802, N806 +# pyright: reportUndefinedVariable=false +# pyright: reportMissingImports=false from typing import Dict, OrderedDict from xml.dom import minidom @@ -63,7 +66,7 @@ class ConfigurationXmlConverter: """ @staticmethod - def blocks_to_xml(blocks: OrderedDict, macros: Dict): + def blocks_to_xml(blocks: OrderedDict, macros: Dict) -> str: """Generates an XML representation for a supplied dictionary of blocks. Args: @@ -110,7 +113,7 @@ def groups_to_xml(groups: OrderedDict, include_none: bool = False) -> str: return minidom.parseString(ElementTree.tostring(root)).toprettyxml() @staticmethod - def iocs_to_xml(iocs: OrderedDict): + def iocs_to_xml(iocs: OrderedDict) -> str: """Generates an XML representation for a supplied list of iocs. Args: @@ -130,7 +133,7 @@ def iocs_to_xml(iocs: OrderedDict): return minidom.parseString(ElementTree.tostring(root)).toprettyxml() @staticmethod - def components_to_xml(comps: OrderedDict): + def components_to_xml(comps: OrderedDict) -> str: """Generates an XML representation for a supplied dictionary of components. Args: @@ -148,7 +151,7 @@ def components_to_xml(comps: OrderedDict): return minidom.parseString(ElementTree.tostring(root)).toprettyxml() @staticmethod - def meta_to_xml(data: MetaData): + def meta_to_xml(data: MetaData) -> str: """Generates an XML representation of the meta data for each configuration. Args: @@ -184,7 +187,7 @@ def meta_to_xml(data: MetaData): return minidom.parseString(ElementTree.tostring(root)).toprettyxml() @staticmethod - def _block_to_xml(root_xml: ElementTree.Element, block: Block, macros: Dict): + def _block_to_xml(root_xml: ElementTree.Element, block: Block, macros: Dict) -> None: """Generates the XML for a block""" name = block.name read_pv = block.pv @@ -236,7 +239,7 @@ def _block_to_xml(root_xml: ElementTree.Element, block: Block, macros: Dict): set_block_val = ElementTree.SubElement(block_xml, TAG_SET_BLOCK_VAL) set_block_val.text = str(block.set_block_val) - + # Alarm Config alarmenabled = ElementTree.SubElement(block_xml, TAG_ALARM_ENABLED) alarmenabled.text = str(block.alarmenabled) @@ -247,9 +250,9 @@ def _block_to_xml(root_xml: ElementTree.Element, block: Block, macros: Dict): alarmdelay.text = str(block.alarmdelay) alarmguidance = ElementTree.SubElement(block_xml, TAG_ALARM_GUIDANCE) alarmguidance.text = block.alarmguidance - + @staticmethod - def _group_to_xml(root_xml: ElementTree, group: Group): + def _group_to_xml(root_xml: ElementTree, group: Group) -> None: """Generates the XML for a group""" grp = ElementTree.SubElement(root_xml, TAG_GROUP) grp.set(TAG_NAME, group.name) @@ -260,7 +263,7 @@ def _group_to_xml(root_xml: ElementTree, group: Group): b.set(TAG_NAME, blk) @staticmethod - def _ioc_to_xml(root_xml: ElementTree.Element, ioc: IOC): + def _ioc_to_xml(root_xml: ElementTree.Element, ioc: IOC) -> None: """Generates the XML for an ioc""" grp = ElementTree.SubElement(root_xml, TAG_IOC) grp.set(TAG_NAME, ioc.name) @@ -283,13 +286,15 @@ def _ioc_to_xml(root_xml: ElementTree.Element, ioc: IOC): value_list_to_xml(ioc.pvsets, grp, TAG_PVSETS, TAG_PVSET) @staticmethod - def _component_to_xml(root_xml: ElementTree.Element, name: str): + def _component_to_xml(root_xml: ElementTree.Element, name: str) -> None: """Generates the XML for a component""" grp = ElementTree.SubElement(root_xml, TAG_COMPONENT) grp.set(TAG_NAME, name) @staticmethod - def blocks_from_xml(root_xml: ElementTree.Element, blocks: OrderedDict, groups: OrderedDict): + def blocks_from_xml( + root_xml: ElementTree.Element, blocks: OrderedDict, groups: OrderedDict + ) -> None: """Populates the supplied dictionary of blocks and groups based on an XML tree. Args: @@ -377,24 +382,33 @@ def blocks_from_xml(root_xml: ElementTree.Element, blocks: OrderedDict, groups: ) if set_block_val is not None: blocks[name.lower()].set_block_val = set_block_val.text - + # Alarm Config - alarmenabled = ConfigurationXmlConverter._find_single_node(b, NS_TAG_BLOCK, TAG_ALARM_ENABLED) + alarmenabled = ConfigurationXmlConverter._find_single_node( + b, NS_TAG_BLOCK, TAG_ALARM_ENABLED + ) if alarmenabled is not None: blocks[name.lower()].alarmenabled = alarmenabled.text == "True" - alarmlatched = ConfigurationXmlConverter._find_single_node(b, NS_TAG_BLOCK, TAG_ALARM_LATCHED) + alarmlatched = ConfigurationXmlConverter._find_single_node( + b, NS_TAG_BLOCK, TAG_ALARM_LATCHED + ) if alarmlatched is not None: blocks[name.lower()].alarmlatched = alarmlatched.text == "True" - alarmdelay = ConfigurationXmlConverter._find_single_node(b, NS_TAG_BLOCK, TAG_ALARM_DELAY) + alarmdelay = ConfigurationXmlConverter._find_single_node( + b, NS_TAG_BLOCK, TAG_ALARM_DELAY + ) if alarmdelay is not None: blocks[name.lower()].alarmdelay = float(alarmdelay.text) - alarmguidance = ConfigurationXmlConverter._find_single_node(b, NS_TAG_BLOCK, TAG_ALARM_GUIDANCE) + alarmguidance = ConfigurationXmlConverter._find_single_node( + b, NS_TAG_BLOCK, TAG_ALARM_GUIDANCE + ) if alarmguidance is not None: blocks[name.lower()].alarmguidance = alarmguidance.text - @staticmethod - def groups_from_xml(root_xml: ElementTree.Element, groups: OrderedDict, blocks: OrderedDict): + def groups_from_xml( + root_xml: ElementTree.Element, groups: OrderedDict, blocks: OrderedDict + ) -> None: """Populates the supplied dictionary of groups and assign blocks based on an XML tree Args: @@ -421,7 +435,8 @@ def groups_from_xml(root_xml: ElementTree.Element, groups: OrderedDict, blocks: for b in blks: name = b.attrib[TAG_NAME] - # Check block is not already in the group. Unlikely, but may be a config was edited by hand... + # Check block is not already in the group. + # Unlikely, but may be a config was edited by hand... if name not in groups[gname_low].blocks: groups[gname_low].blocks.append(name) if name.lower() in blocks.keys(): @@ -432,7 +447,7 @@ def groups_from_xml(root_xml: ElementTree.Element, groups: OrderedDict, blocks: groups[KEY_NONE].blocks.remove(name) @staticmethod - def ioc_from_xml(root_xml: ElementTree.Element, iocs: OrderedDict): + def ioc_from_xml(root_xml: ElementTree.Element, iocs: OrderedDict) -> None: """Populates the supplied dictionary of IOCs based on an XML tree. Args: @@ -484,7 +499,7 @@ def ioc_from_xml(root_xml: ElementTree.Element, iocs: OrderedDict): raise Exception("Tag not found in ioc.xml (" + str(err) + ")") @staticmethod - def components_from_xml(root_xml: ElementTree.Element, components: OrderedDict): + def components_from_xml(root_xml: ElementTree.Element, components: OrderedDict) -> None: """Populates the supplied dictionary of components based on an XML tree. Args: @@ -511,7 +526,7 @@ def get_configuresBlockGWAndArchiver_from_xml(root_xml: ElementTree.Element) -> return False @staticmethod - def meta_from_xml(root_xml: ElementTree.Element, data: MetaData): + def meta_from_xml(root_xml: ElementTree.Element, data: MetaData) -> None: """Populates the supplied MetaData object based on an XML tree. Args: @@ -548,10 +563,13 @@ def meta_from_xml(root_xml: ElementTree.Element, data: MetaData): data.history = [e.text for e in edits] @staticmethod - def _find_all_nodes(root: ElementTree.Element, tag: str, name: str): + def _find_all_nodes( + root: ElementTree.Element, tag: str, name: str + ) -> list[ElementTree.Element]: """Finds all the nodes regardless of whether it has a namespace or not. - For example the name space for IOCs is xmlns:ioc="http://epics.isis.rl.ac.uk/schema/iocs/1.0" + For example the name space for IOCs is + xmlns:ioc="http://epics.isis.rl.ac.uk/schema/iocs/1.0" Args: root: The XML tree object @@ -588,7 +606,7 @@ def _find_single_node(root: ElementTree.Element, tag: str, name: str) -> Element return node @staticmethod - def _display(child, index): + def _display(child: ElementTree.Element, index: int) -> dict: return { "index": index, "name": ConfigurationXmlConverter._find_single_node(child, "banner", "name").text, @@ -598,7 +616,7 @@ def _display(child, index): } @staticmethod - def _button(child, index): + def _button(child: ElementTree.Element, index: int) -> dict: return { "index": index, "name": ConfigurationXmlConverter._find_single_node(child, "banner", "name").text, @@ -619,7 +637,7 @@ def _button(child, index): } @staticmethod - def banner_config_from_xml(root): + def banner_config_from_xml(root: None | ElementTree.Element) -> list[Any] | dict[str, list]: """ Parses the banner config XML to produce a banner config dictionary @@ -629,7 +647,8 @@ def banner_config_from_xml(root): Returns: A dictionary with two entries, the banner items and the banner buttons. The items have the properties name, pv, local. - The buttons have the properties name, pv, local, pvValue, textColour, buttonColour, width, height. + The buttons have the properties name, pv, local, pvValue, textColour, buttonColour, + width, height. """ if root is None: return [] From be8d30902aa93d6ad3703fc2afcc308a3587a69f Mon Sep 17 00:00:00 2001 From: Chsudeepta Date: Fri, 21 Nov 2025 17:43:30 +0000 Subject: [PATCH 05/22] some ruff stuff fixes --- BlockServer/config/xml_converter.py | 10 +++++----- BlockServer/test_modules/test_configuration_xml.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/BlockServer/config/xml_converter.py b/BlockServer/config/xml_converter.py index bf36db2a..bdf235f0 100644 --- a/BlockServer/config/xml_converter.py +++ b/BlockServer/config/xml_converter.py @@ -13,7 +13,7 @@ # along with this program; if not, you can obtain a copy from # https://www.eclipse.org/org/documents/epl-v10.php or # http://opensource.org/licenses/eclipse-1.0.php -# ruff: noqa: F403, F405, N802, N806 +# ruff: noqa: F403, F405, N802, N806, I001 # pyright: reportUndefinedVariable=false # pyright: reportMissingImports=false from typing import Dict, OrderedDict @@ -388,22 +388,22 @@ def blocks_from_xml( b, NS_TAG_BLOCK, TAG_ALARM_ENABLED ) if alarmenabled is not None: - blocks[name.lower()].alarmenabled = alarmenabled.text == "True" + blocks[name.lower()].alarmenabled=alarmenabled.text == "True" # pyright: ignore alarmlatched = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_LATCHED ) if alarmlatched is not None: - blocks[name.lower()].alarmlatched = alarmlatched.text == "True" + blocks[name.lower()].alarmlatched=alarmlatched.text == "True" # pyright: ignore alarmdelay = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_DELAY ) if alarmdelay is not None: - blocks[name.lower()].alarmdelay = float(alarmdelay.text) + blocks[name.lower()].alarmdelay = float(alarmdelay.text) # pyright: ignore alarmguidance = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_GUIDANCE ) if alarmguidance is not None: - blocks[name.lower()].alarmguidance = alarmguidance.text + blocks[name.lower()].alarmguidance = alarmguidance.text # pyright: ignore @staticmethod def groups_from_xml( diff --git a/BlockServer/test_modules/test_configuration_xml.py b/BlockServer/test_modules/test_configuration_xml.py index e53e4a3a..04137f82 100644 --- a/BlockServer/test_modules/test_configuration_xml.py +++ b/BlockServer/test_modules/test_configuration_xml.py @@ -13,7 +13,7 @@ # Along with this program; if not, you can obtain a copy from # https://www.eclipse.org/org/documents/epl-v10.php or # http://opensource.org/licenses/eclipse-1.0.php - +# ruff: noqa: I001 import re import unittest from collections import OrderedDict From 123e4452f8ea0d12dec1c0a460b51506958056c4 Mon Sep 17 00:00:00 2001 From: Chsudeepta Date: Fri, 21 Nov 2025 17:56:12 +0000 Subject: [PATCH 06/22] some ruff stuff fixes --- BlockServer/config/xml_converter.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/BlockServer/config/xml_converter.py b/BlockServer/config/xml_converter.py index bdf235f0..12754f99 100644 --- a/BlockServer/config/xml_converter.py +++ b/BlockServer/config/xml_converter.py @@ -13,7 +13,7 @@ # along with this program; if not, you can obtain a copy from # https://www.eclipse.org/org/documents/epl-v10.php or # http://opensource.org/licenses/eclipse-1.0.php -# ruff: noqa: F403, F405, N802, N806, I001 +# ruff: noqa: F403, F405, N802, N806, I001 # pyright: reportUndefinedVariable=false # pyright: reportMissingImports=false from typing import Dict, OrderedDict @@ -388,22 +388,22 @@ def blocks_from_xml( b, NS_TAG_BLOCK, TAG_ALARM_ENABLED ) if alarmenabled is not None: - blocks[name.lower()].alarmenabled=alarmenabled.text == "True" # pyright: ignore + blocks[name.lower()].alarmenabled = alarmenabled.text == "True" # pyright: ignore alarmlatched = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_LATCHED ) if alarmlatched is not None: - blocks[name.lower()].alarmlatched=alarmlatched.text == "True" # pyright: ignore + blocks[name.lower()].alarmlatched = alarmlatched.text == "True" # pyright: ignore alarmdelay = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_DELAY ) if alarmdelay is not None: - blocks[name.lower()].alarmdelay = float(alarmdelay.text) # pyright: ignore + blocks[name.lower()].alarmdelay = float(alarmdelay.text) # pyright: ignore alarmguidance = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_GUIDANCE ) if alarmguidance is not None: - blocks[name.lower()].alarmguidance = alarmguidance.text # pyright: ignore + blocks[name.lower()].alarmguidance = alarmguidance.text # pyright: ignore @staticmethod def groups_from_xml( @@ -637,7 +637,7 @@ def _button(child: ElementTree.Element, index: int) -> dict: } @staticmethod - def banner_config_from_xml(root: None | ElementTree.Element) -> list[Any] | dict[str, list]: + def banner_config_from_xml(root: None | ElementTree.Element) -> list | dict[str, list]: """ Parses the banner config XML to produce a banner config dictionary From 26494d222597b6f5462dc2ea30697c12782dc188 Mon Sep 17 00:00:00 2001 From: Chsudeepta Date: Tue, 17 Feb 2026 10:50:45 +0000 Subject: [PATCH 07/22] Fixed some linter comments --- BlockServer/config/block.py | 2 +- BlockServer/test_modules/test_configuration_xml.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/BlockServer/config/block.py b/BlockServer/config/block.py index dc9d7b20..00ea9dfa 100644 --- a/BlockServer/config/block.py +++ b/BlockServer/config/block.py @@ -13,7 +13,7 @@ # along with this program; if not, you can obtain a copy from # https://www.eclipse.org/org/documents/epl-v10.php or # http://opensource.org/licenses/eclipse-1.0.php -# pyright: reportMissingImports=false + from typing import Dict, Union from server_common.helpers import PVPREFIX_MACRO diff --git a/BlockServer/test_modules/test_configuration_xml.py b/BlockServer/test_modules/test_configuration_xml.py index 04137f82..54ec8421 100644 --- a/BlockServer/test_modules/test_configuration_xml.py +++ b/BlockServer/test_modules/test_configuration_xml.py @@ -13,19 +13,20 @@ # Along with this program; if not, you can obtain a copy from # https://www.eclipse.org/org/documents/epl-v10.php or # http://opensource.org/licenses/eclipse-1.0.php -# ruff: noqa: I001 + import re import unittest from collections import OrderedDict from xml.etree import ElementTree +from server_common.helpers import MACROS + from BlockServer.config.block import Block from BlockServer.config.configuration import Configuration from BlockServer.config.group import Group from BlockServer.config.ioc import IOC from BlockServer.config.metadata import MetaData from BlockServer.config.xml_converter import ConfigurationXmlConverter -from server_common.helpers import MACROS BLOCKS_XML = """ From 61b732c2c6ab57a286238ca8a41adf3e525344bd Mon Sep 17 00:00:00 2001 From: Chsudeepta Date: Wed, 8 Apr 2026 15:28:25 +0100 Subject: [PATCH 08/22] Ruff fixes --- BlockServer/config/xml_converter.py | 89 +++++++++++++++++++++-------- 1 file changed, 65 insertions(+), 24 deletions(-) diff --git a/BlockServer/config/xml_converter.py b/BlockServer/config/xml_converter.py index 12754f99..58fe6cfb 100644 --- a/BlockServer/config/xml_converter.py +++ b/BlockServer/config/xml_converter.py @@ -13,19 +13,60 @@ # along with this program; if not, you can obtain a copy from # https://www.eclipse.org/org/documents/epl-v10.php or # http://opensource.org/licenses/eclipse-1.0.php -# ruff: noqa: F403, F405, N802, N806, I001 -# pyright: reportUndefinedVariable=false -# pyright: reportMissingImports=false + from typing import Dict, OrderedDict from xml.dom import minidom +from xml.etree import ElementTree + +from server_common.helpers import PVPREFIX_MACRO +from server_common.utilities import parse_boolean, value_list_to_xml from BlockServer.config.block import Block from BlockServer.config.group import Group from BlockServer.config.ioc import IOC from BlockServer.config.metadata import MetaData -from BlockServer.core.constants import * -from server_common.helpers import PVPREFIX_MACRO -from server_common.utilities import * +from BlockServer.core.constants import ( + GRP_NONE, + SIMLEVELS, + TAG_ALARM_DELAY, + TAG_ALARM_ENABLED, + TAG_ALARM_GUIDANCE, + TAG_ALARM_LATCHED, + TAG_AUTOSTART, + TAG_BLOCK, + TAG_BLOCKS, + TAG_COMPONENT, + TAG_COMPONENTS, + TAG_EDIT, + TAG_EDITS, + TAG_GROUP, + TAG_GROUPS, + TAG_IOC, + TAG_IOCS, + TAG_LOCAL, + TAG_LOG_DEADBAND, + TAG_LOG_PERIODIC, + TAG_LOG_RATE, + TAG_MACRO, + TAG_MACROS, + TAG_NAME, + TAG_PV, + TAG_PVS, + TAG_PVSET, + TAG_PVSETS, + TAG_READ_PV, + TAG_REMOTE_PREFIX, + TAG_RESTART, + TAG_RUNCONTROL_ENABLED, + TAG_RUNCONTROL_HIGH, + TAG_RUNCONTROL_LOW, + TAG_RUNCONTROL_SUSPEND_ON_INVALID, + TAG_SET_BLOCK, + TAG_SET_BLOCK_VAL, + TAG_SIMLEVEL, + TAG_VALUE, + TAG_VISIBLE, +) KEY_NONE = GRP_NONE.lower() TAG_ENABLED = "enabled" @@ -388,22 +429,22 @@ def blocks_from_xml( b, NS_TAG_BLOCK, TAG_ALARM_ENABLED ) if alarmenabled is not None: - blocks[name.lower()].alarmenabled = alarmenabled.text == "True" # pyright: ignore + blocks[name.lower()].alarmenabled = alarmenabled.text == "True" alarmlatched = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_LATCHED ) if alarmlatched is not None: - blocks[name.lower()].alarmlatched = alarmlatched.text == "True" # pyright: ignore + blocks[name.lower()].alarmlatched = alarmlatched.text == "True" alarmdelay = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_DELAY ) if alarmdelay is not None: - blocks[name.lower()].alarmdelay = float(alarmdelay.text) # pyright: ignore + blocks[name.lower()].alarmdelay = float(alarmdelay.text) alarmguidance = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_GUIDANCE ) if alarmguidance is not None: - blocks[name.lower()].alarmguidance = alarmguidance.text # pyright: ignore + blocks[name.lower()].alarmguidance = alarmguidance.text @staticmethod def groups_from_xml( @@ -515,13 +556,13 @@ def components_from_xml(root_xml: ElementTree.Element, components: OrderedDict) components[n.lower()] = n @staticmethod - def get_configuresBlockGWAndArchiver_from_xml(root_xml: ElementTree.Element) -> bool: - configuresBlockGWAndArchiver = root_xml.find("./" + TAG_CONFIGURES_BLOCK_GW_AND_ARCHIVER) + def get_configures_block_gw_and_archiver_from_xml(root_xml: ElementTree.Element) -> bool: + configureblock_gw_and_archiver = root_xml.find("./" + TAG_CONFIGURES_BLOCK_GW_AND_ARCHIVER) if ( - configuresBlockGWAndArchiver is not None - and configuresBlockGWAndArchiver.text is not None + configureblock_gw_and_archiver is not None + and configureblock_gw_and_archiver.text is not None ): - return configuresBlockGWAndArchiver.text.lower() == "true" + return configureblock_gw_and_archiver.text.lower() == "true" else: return False @@ -541,21 +582,21 @@ def meta_from_xml(root_xml: ElementTree.Element, data: MetaData) -> None: if synoptic is not None: data.synoptic = synoptic.text if synoptic.text is not None else "" - isProtected = root_xml.find("./" + TAG_PROTECTED) - if isProtected is not None: - if isProtected.text is not None: - data.isProtected = isProtected.text.lower() == "true" + protected = root_xml.find("./" + TAG_PROTECTED) + if protected is not None: + if protected.text is not None: + data.isProtected = protected.text.lower() == "true" else: data.isProtected = False data.configuresBlockGWAndArchiver = ( - ConfigurationXmlConverter.get_configuresBlockGWAndArchiver_from_xml(root_xml) + ConfigurationXmlConverter.get_configures_block_gw_and_archiver_from_xml(root_xml) ) - isDynamic = root_xml.find("./" + TAG_DYNAMIC) - if isDynamic is not None: - if isDynamic.text is not None: - data.isDynamic = isDynamic.text.lower() == "true" + dynamic = root_xml.find("./" + TAG_DYNAMIC) + if dynamic is not None: + if dynamic.text is not None: + data.isDynamic = dynamic.text.lower() == "true" else: data.isDynamic = False From 806efc21d17bf805034685558b3ded738039a668 Mon Sep 17 00:00:00 2001 From: vux62295 Date: Fri, 3 Jul 2026 17:35:16 +0100 Subject: [PATCH 09/22] Reformatetd to satisfy ruff's bloated ego --- BlockServer/config/xml_converter.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/BlockServer/config/xml_converter.py b/BlockServer/config/xml_converter.py index 7af74b8f..40500e29 100644 --- a/BlockServer/config/xml_converter.py +++ b/BlockServer/config/xml_converter.py @@ -435,22 +435,22 @@ def blocks_from_xml( b, NS_TAG_BLOCK, TAG_ALARM_ENABLED ) if alarmenabled is not None: - blocks[name.lower()].alarmenabled = alarmenabled.text == "True" + blocks[name.lower()].alarmenabled = alarmenabled.text == "True" alarmlatched = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_LATCHED ) if alarmlatched is not None: - blocks[name.lower()].alarmlatched = alarmlatched.text == "True" + blocks[name.lower()].alarmlatched = alarmlatched.text == "True" alarmdelay = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_DELAY ) if alarmdelay is not None: - blocks[name.lower()].alarmdelay = float(alarmdelay.text) + blocks[name.lower()].alarmdelay = float(alarmdelay.text) alarmguidance = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_GUIDANCE ) if alarmguidance is not None: - blocks[name.lower()].alarmguidance = alarmguidance.text + blocks[name.lower()].alarmguidance = alarmguidance.text @staticmethod def groups_from_xml( From dcf30445042cd1631731dd3d3141ebfafd25f2f6 Mon Sep 17 00:00:00 2001 From: vux62295 Date: Fri, 3 Jul 2026 17:41:55 +0100 Subject: [PATCH 10/22] Reformatetd to satisfy ruff's bloated ego --- BlockServer/config/xml_converter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/BlockServer/config/xml_converter.py b/BlockServer/config/xml_converter.py index 40500e29..118301b4 100644 --- a/BlockServer/config/xml_converter.py +++ b/BlockServer/config/xml_converter.py @@ -572,6 +572,7 @@ def get_configures_block_gw_and_archiver_from_xml(root_xml: ElementTree.Element) ): return configureblock_gw_and_archiver.text.lower() == "true" + @staticmethod def get_configures_block_g_w_and_archiver(root_xml: ElementTree.Element) -> bool: configures_block_g_w_and_archiver = root_xml.find( "./" + TAG_CONFIGURES_BLOCK_GW_AND_ARCHIVER From f546db325c149ebb1611d5ad1e61578779e4a919 Mon Sep 17 00:00:00 2001 From: vux62295 Date: Fri, 3 Jul 2026 18:00:44 +0100 Subject: [PATCH 11/22] Reformatetd to satisfy ruff's bloated ego --- BlockServer/config/xml_converter.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BlockServer/config/xml_converter.py b/BlockServer/config/xml_converter.py index 118301b4..e94e4812 100644 --- a/BlockServer/config/xml_converter.py +++ b/BlockServer/config/xml_converter.py @@ -571,6 +571,8 @@ def get_configures_block_gw_and_archiver_from_xml(root_xml: ElementTree.Element) and configureblock_gw_and_archiver.text is not None ): return configureblock_gw_and_archiver.text.lower() == "true" + else: + return False @staticmethod def get_configures_block_g_w_and_archiver(root_xml: ElementTree.Element) -> bool: From 93864f9abe50175e0c437867bef3202eaf37bb9e Mon Sep 17 00:00:00 2001 From: vux62295 Date: Fri, 3 Jul 2026 21:28:26 +0100 Subject: [PATCH 12/22] Merged with master --- BlockServer/config/xml_converter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BlockServer/config/xml_converter.py b/BlockServer/config/xml_converter.py index e94e4812..261d81b3 100644 --- a/BlockServer/config/xml_converter.py +++ b/BlockServer/config/xml_converter.py @@ -444,7 +444,7 @@ def blocks_from_xml( alarmdelay = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_DELAY ) - if alarmdelay is not None: + if alarmdelay is not None and alarmdelay.text is not None: blocks[name.lower()].alarmdelay = float(alarmdelay.text) alarmguidance = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_GUIDANCE @@ -572,7 +572,7 @@ def get_configures_block_gw_and_archiver_from_xml(root_xml: ElementTree.Element) ): return configureblock_gw_and_archiver.text.lower() == "true" else: - return False + return False @staticmethod def get_configures_block_g_w_and_archiver(root_xml: ElementTree.Element) -> bool: From 9431bba122b0d3d40c50811c88660caba91c555e Mon Sep 17 00:00:00 2001 From: vux62295 Date: Mon, 20 Jul 2026 16:00:08 +0100 Subject: [PATCH 13/22] Updated as per review comments --- BlockServer/config/block.py | 44 ++++++++++--------- BlockServer/config/xml_converter.py | 65 ++++++++++------------------- 2 files changed, 46 insertions(+), 63 deletions(-) diff --git a/BlockServer/config/block.py b/BlockServer/config/block.py index 09fb7206..eee1f4e4 100644 --- a/BlockServer/config/block.py +++ b/BlockServer/config/block.py @@ -34,10 +34,10 @@ class Block: log_periodic (bool): Whether the block is sampled periodically in the archiver log_rate (float): Time between archive samples (in seconds) log_deadband (float): Deadband for the block to be archived - alarmenabled (bool): Whether the alarm should be enabled - alarmlatched (bool): Whether the alarm should be latched - alarmdelay (float): The delay for trigerring alarm - alarmguidance (string): The guidance for the alarm + alarm_enabled (bool): Whether the alarm should be enabled + alarm_latched (bool): Whether the alarm should be latched + alarm_delay (float): The delay for triggering alarm + alarm_guidance (string): The guidance for the alarm """ @@ -57,10 +57,10 @@ def __init__( log_deadband: float = 0, set_block: bool = False, set_block_val: str | None = None, - alarmenabled: bool = False, - alarmlatched: bool = False, - alarmdelay: float | None = None, - alarmguidance: str | None = None, + alarm_enabled: bool = False, + alarm_latched: bool = False, + alarm_delay: float | None = None, + alarm_guidance: str | None = None, ) -> None: """Constructor. @@ -79,10 +79,10 @@ def __init__( log_deadband: Deadband for the block to be archived set_block: whether the block should be set upon config change set_block_val: what the block should be set to upon config change - alarmenabled (bool): Whether the alarm should be enabled - alarmlatched (bool): Whether the alarm should be latched - alarmdelay (float): The delay for trigerring alarm - alarmguidance (string): The guidance for the alarm + alarm_enabled: Whether the alarm should be enabled + alarm_latched: Whether the alarm should be latched + alarm_delay: The delay for triggering alarm + alarm_guidance: The guidance for the alarm """ self.name = name self.pv = pv @@ -98,10 +98,10 @@ def __init__( self.log_deadband = log_deadband self.set_block = set_block self.set_block_val = set_block_val - self.alarmenabled = alarmenabled - self.alarmlatched = alarmlatched - self.alarmdelay = alarmdelay - self.alarmguidance = alarmguidance + self.alarm_enabled = alarm_enabled + self.alarm_latched = alarm_latched + self.alarm_delay = alarm_delay + self.alarm_guidance = alarm_guidance def _get_pv(self) -> str: pv_name = self.pv @@ -150,10 +150,10 @@ def to_dict(self) -> Dict[str, Union[str, float, bool, None]]: "suspend_on_invalid": self.rc_suspend_on_invalid, "set_block": self.set_block, "set_block_val": self.set_block_val, - "alarmenabled": self.alarmenabled, - "alarmlatched": self.alarmlatched, - "alarmdelay": self.alarmdelay, - "alarmguidance": self.alarmguidance, + "alarm_enabled": self.alarm_enabled, + "alarm_latched": self.alarm_latched, + "alarm_delay": self.alarm_delay, + "alarm_guidance": self.alarm_guidance, } @@ -169,3 +169,7 @@ class BlockKwargs(TypedDict, total=False): log_deadband: float set_block: bool set_block_val: str | None + alarm_enabled: bool | None + alarm_latched: bool | None + alarm_delay: float | None + alarm_guidance: str | None diff --git a/BlockServer/config/xml_converter.py b/BlockServer/config/xml_converter.py index 261d81b3..e875c659 100644 --- a/BlockServer/config/xml_converter.py +++ b/BlockServer/config/xml_converter.py @@ -282,15 +282,15 @@ def _block_to_xml(root_xml: ElementTree.Element, block: Block, macros: Dict) -> set_block_val.text = str(block.set_block_val) # Alarm Config - alarmenabled = ElementTree.SubElement(block_xml, TAG_ALARM_ENABLED) - alarmenabled.text = str(block.alarmenabled) - alarmlatched = ElementTree.SubElement(block_xml, TAG_ALARM_LATCHED) - alarmlatched.text = str(block.alarmlatched) - if block.alarmdelay is not None: - alarmdelay = ElementTree.SubElement(block_xml, TAG_ALARM_DELAY) - alarmdelay.text = str(block.alarmdelay) - alarmguidance = ElementTree.SubElement(block_xml, TAG_ALARM_GUIDANCE) - alarmguidance.text = block.alarmguidance + alarm_enabled = ElementTree.SubElement(block_xml, TAG_ALARM_ENABLED) + alarm_enabled.text = str(block.alarm_enabled) + alarm_latched = ElementTree.SubElement(block_xml, TAG_ALARM_LATCHED) + alarm_latched.text = str(block.alarm_latched) + if block.alarm_delay is not None: + alarm_delay = ElementTree.SubElement(block_xml, TAG_ALARM_DELAY) + alarm_delay.text = str(block.alarm_delay) + alarm_guidance = ElementTree.SubElement(block_xml, TAG_ALARM_GUIDANCE) + alarm_guidance.text = block.alarm_guidance @staticmethod def _group_to_xml(root_xml: ElementTree.Element, group: Group) -> None: @@ -431,26 +431,26 @@ def blocks_from_xml( blocks[name.lower()].set_block_val = set_block_val.text # Alarm Config - alarmenabled = ConfigurationXmlConverter._find_single_node( + alarm_enabled = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_ENABLED ) - if alarmenabled is not None: - blocks[name.lower()].alarmenabled = alarmenabled.text == "True" - alarmlatched = ConfigurationXmlConverter._find_single_node( + if alarm_enabled is not None: + blocks[name.lower()].alarm_enabled = alarm_enabled.text == "True" + alarm_latched = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_LATCHED ) - if alarmlatched is not None: - blocks[name.lower()].alarmlatched = alarmlatched.text == "True" - alarmdelay = ConfigurationXmlConverter._find_single_node( + if alarm_latched is not None: + blocks[name.lower()].alarmlatched = alarm_latched.text == "True" + alarm_delay = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_DELAY ) - if alarmdelay is not None and alarmdelay.text is not None: - blocks[name.lower()].alarmdelay = float(alarmdelay.text) - alarmguidance = ConfigurationXmlConverter._find_single_node( + if alarm_delay is not None and alarm_delay.text is not None: + blocks[name.lower()].alarm_delay = float(alarm_delay.text) + alarm_guidance = ConfigurationXmlConverter._find_single_node( b, NS_TAG_BLOCK, TAG_ALARM_GUIDANCE ) - if alarmguidance is not None: - blocks[name.lower()].alarmguidance = alarmguidance.text + if alarm_guidance is not None: + blocks[name.lower()].alarm_guidance = alarm_guidance.text @staticmethod def groups_from_xml( @@ -563,17 +563,6 @@ def components_from_xml(root_xml: ElementTree.Element, components: OrderedDict) if n is not None and n != "": components[n.lower()] = n - @staticmethod - def get_configures_block_gw_and_archiver_from_xml(root_xml: ElementTree.Element) -> bool: - configureblock_gw_and_archiver = root_xml.find("./" + TAG_CONFIGURES_BLOCK_GW_AND_ARCHIVER) - if ( - configureblock_gw_and_archiver is not None - and configureblock_gw_and_archiver.text is not None - ): - return configureblock_gw_and_archiver.text.lower() == "true" - else: - return False - @staticmethod def get_configures_block_g_w_and_archiver(root_xml: ElementTree.Element) -> bool: configures_block_g_w_and_archiver = root_xml.find( @@ -603,10 +592,6 @@ def meta_from_xml(root_xml: ElementTree.Element, data: MetaData) -> None: if synoptic is not None: data.synoptic = synoptic.text if synoptic.text is not None else "" - protected = root_xml.find("./" + TAG_PROTECTED) - if protected is not None: - if protected.text is not None: - data.isProtected = protected.text.lower() == "true" is_protected = root_xml.find("./" + TAG_PROTECTED) if is_protected is not None: if is_protected.text is not None: @@ -615,14 +600,8 @@ def meta_from_xml(root_xml: ElementTree.Element, data: MetaData) -> None: data.isProtected = False data.configuresBlockGWAndArchiver = ( - ConfigurationXmlConverter.get_configures_block_gw_and_archiver_from_xml(root_xml) - ) - - dynamic = root_xml.find("./" + TAG_DYNAMIC) - if dynamic is not None: - if dynamic.text is not None: - data.isDynamic = dynamic.text.lower() == "true" ConfigurationXmlConverter.get_configures_block_g_w_and_archiver(root_xml) + ) is_dynamic = root_xml.find("./" + TAG_DYNAMIC) if is_dynamic is not None: From ec7b2aa6e8804c4e2a65959952e9dbef0bcf0aa8 Mon Sep 17 00:00:00 2001 From: vux62295 Date: Thu, 23 Jul 2026 18:28:21 +0100 Subject: [PATCH 14/22] Added Delay in the test file --- BlockServer/test_modules/test_configuration_xml.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/BlockServer/test_modules/test_configuration_xml.py b/BlockServer/test_modules/test_configuration_xml.py index 54ec8421..11ef98af 100644 --- a/BlockServer/test_modules/test_configuration_xml.py +++ b/BlockServer/test_modules/test_configuration_xml.py @@ -47,6 +47,7 @@ None False False + 5.0 @@ -65,6 +66,7 @@ None False False + 5.0 @@ -83,6 +85,7 @@ None False False + 5.0 @@ -101,6 +104,7 @@ None False False + 5.0 """ From cccdd8a0d7aef50b3bc1f851ab35384525595ce2 Mon Sep 17 00:00:00 2001 From: vux62295 Date: Fri, 24 Jul 2026 13:40:19 +0100 Subject: [PATCH 15/22] Passed test cases --- BlockServer/test_modules/test_configuration_xml.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/BlockServer/test_modules/test_configuration_xml.py b/BlockServer/test_modules/test_configuration_xml.py index 11ef98af..54ec8421 100644 --- a/BlockServer/test_modules/test_configuration_xml.py +++ b/BlockServer/test_modules/test_configuration_xml.py @@ -47,7 +47,6 @@ None False False - 5.0 @@ -66,7 +65,6 @@ None False False - 5.0 @@ -85,7 +83,6 @@ None False False - 5.0 @@ -104,7 +101,6 @@ None False False - 5.0 """ From 8431a91a420ed0e80bcc424c66111cd823c76099 Mon Sep 17 00:00:00 2001 From: vux62295 Date: Mon, 27 Jul 2026 12:53:17 +0100 Subject: [PATCH 16/22] Fixed some ruff issues --- BlockServer/config/xml_converter.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/BlockServer/config/xml_converter.py b/BlockServer/config/xml_converter.py index e875c659..e54b7d19 100644 --- a/BlockServer/config/xml_converter.py +++ b/BlockServer/config/xml_converter.py @@ -14,7 +14,7 @@ # https://www.eclipse.org/org/documents/epl-v10.php or # http://opensource.org/licenses/eclipse-1.0.php -from typing import Dict, List, OrderedDict +from collections import OrderedDict from xml.dom import minidom from xml.etree import ElementTree @@ -107,7 +107,7 @@ class ConfigurationXmlConverter: """ @staticmethod - def blocks_to_xml(blocks: OrderedDict, macros: Dict) -> str: + def blocks_to_xml(blocks: OrderedDict, macros: dict) -> str: """Generates an XML representation for a supplied dictionary of blocks. Args: @@ -149,7 +149,7 @@ def groups_to_xml(groups: OrderedDict, include_none: bool = False) -> str: ConfigurationXmlConverter._group_to_xml(root, group) # If we are adding the None group it should go at the end - if include_none and KEY_NONE in groups.keys(): + if include_none and KEY_NONE in groups: ConfigurationXmlConverter._group_to_xml(root, groups[KEY_NONE]) return minidom.parseString(ElementTree.tostring(root)).toprettyxml() @@ -167,7 +167,7 @@ def iocs_to_xml(iocs: OrderedDict) -> str: root.attrib["xmlns"] = SCHEMA_PATH + IOC_SCHEMA root.attrib["xmlns:ioc"] = SCHEMA_PATH + IOC_SCHEMA root.attrib["xmlns:xi"] = "http://www.w3.org/2001/XInclude" - for name in iocs.keys(): + for name in iocs: # Don't save if in component if iocs[name].component is None: ConfigurationXmlConverter._ioc_to_xml(root, iocs[name]) @@ -228,7 +228,7 @@ def meta_to_xml(data: MetaData) -> str: return minidom.parseString(ElementTree.tostring(root)).toprettyxml() @staticmethod - def _block_to_xml(root_xml: ElementTree.Element, block: Block, macros: Dict) -> None: + def _block_to_xml(root_xml: ElementTree.Element, block: Block, macros: dict) -> None: """Generates the XML for a block""" name = block.name read_pv = block.pv @@ -474,7 +474,7 @@ def groups_from_xml( gname_low = gname.lower() # Add the group to the dict unless it already exists (i.e. the group is defined twice) - if gname_low not in groups.keys(): + if gname_low not in groups: groups[gname_low] = Group(gname, gcomp) blks = ConfigurationXmlConverter._find_all_nodes(g, NS_TAG_GROUP, TAG_BLOCK) @@ -486,7 +486,7 @@ def groups_from_xml( # Unlikely, but may be a config was edited by hand... if name not in groups[gname_low].blocks: groups[gname_low].blocks.append(name) - if name.lower() in blocks.keys(): + if name.lower() in blocks: blocks[name.lower()].group = gname # Remove the block from the NONE group @@ -616,7 +616,7 @@ def meta_from_xml(root_xml: ElementTree.Element, data: MetaData) -> None: @staticmethod def _find_all_nodes( root: ElementTree.Element, tag: str, name: str - ) -> List[ElementTree.Element]: + ) -> list[ElementTree.Element]: """Finds all the nodes regardless of whether it has a namespace or not. For example the name space for IOCs is @@ -680,7 +680,7 @@ def _find_single_node_with_none_check( return node @staticmethod - def _display(child: ElementTree.Element, index: int) -> Dict[str, str | int | None]: + def _display(child: ElementTree.Element, index: int) -> dict[str, str | int | None]: return { "index": index, "name": ConfigurationXmlConverter._find_single_node_with_none_check( @@ -698,7 +698,7 @@ def _display(child: ElementTree.Element, index: int) -> Dict[str, str | int | No } @staticmethod - def _button(child: ElementTree.Element, index: int) -> Dict[str, str | int | None]: + def _button(child: ElementTree.Element, index: int) -> dict[str, str | int | None]: return { "index": index, "name": ConfigurationXmlConverter._find_single_node_with_none_check( @@ -733,7 +733,7 @@ def _button(child: ElementTree.Element, index: int) -> Dict[str, str | int | Non @staticmethod def banner_config_from_xml( root: ElementTree.Element, - ) -> Dict[str, List[Dict[str, str | int | None]]]: + ) -> dict[str, list[dict[str, str | int | None]]]: """ Parses the banner config XML to produce a banner config dictionary From a3dddacf8db56ba38c681a20e1ba8b7f41aaeb5f Mon Sep 17 00:00:00 2001 From: vux62295 Date: Mon, 27 Jul 2026 13:40:08 +0100 Subject: [PATCH 17/22] Fixed pyright --- BlockServer/config/block.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BlockServer/config/block.py b/BlockServer/config/block.py index eee1f4e4..f11497ca 100644 --- a/BlockServer/config/block.py +++ b/BlockServer/config/block.py @@ -14,7 +14,7 @@ # https://www.eclipse.org/org/documents/epl-v10.php or # http://opensource.org/licenses/eclipse-1.0.php -from typing import Dict, TypedDict, Union +from typing import TypedDict, Union from server_common.helpers import PVPREFIX_MACRO @@ -129,7 +129,7 @@ def __str__(self) -> str: f"RCHigh: {self.rc_highlimit}{set_block_str}" ) - def to_dict(self) -> Dict[str, Union[str, float, bool, None]]: + def to_dict(self) -> dict[str, Union[str, float, bool, None]]: """Puts the block's details into a dictionary. Returns: From cc1d9f5fb83f113e85bd6ff9745189fb3b1f8dff Mon Sep 17 00:00:00 2001 From: vux62295 Date: Mon, 27 Jul 2026 14:18:08 +0100 Subject: [PATCH 18/22] More ruff fixes --- BlockServer/config/block.py | 2 +- BlockServer/config/xml_converter.py | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/BlockServer/config/block.py b/BlockServer/config/block.py index f11497ca..251845af 100644 --- a/BlockServer/config/block.py +++ b/BlockServer/config/block.py @@ -129,7 +129,7 @@ def __str__(self) -> str: f"RCHigh: {self.rc_highlimit}{set_block_str}" ) - def to_dict(self) -> dict[str, Union[str, float, bool, None]]: + def to_dict(self) -> dict[str, str | float | bool | None]: """Puts the block's details into a dictionary. Returns: diff --git a/BlockServer/config/xml_converter.py b/BlockServer/config/xml_converter.py index e54b7d19..7e76ec26 100644 --- a/BlockServer/config/xml_converter.py +++ b/BlockServer/config/xml_converter.py @@ -121,7 +121,7 @@ def blocks_to_xml(blocks: OrderedDict, macros: dict) -> str: root.attrib["xmlns"] = SCHEMA_PATH + BLOCK_SCHEMA root.attrib["xmlns:blk"] = SCHEMA_PATH + BLOCK_SCHEMA root.attrib["xmlns:xi"] = "http://www.w3.org/2001/XInclude" - for name, block in blocks.items(): + for block in blocks.items(): # Don't save if in component if block.component is None or block.component is False: ConfigurationXmlConverter._block_to_xml(root, block, macros) @@ -187,7 +187,7 @@ def components_to_xml(comps: OrderedDict) -> str: root.attrib["xmlns"] = SCHEMA_PATH + COMPONENT_SCHEMA root.attrib["xmlns:comp"] = SCHEMA_PATH + COMPONENT_SCHEMA root.attrib["xmlns:xi"] = "http://www.w3.org/2001/XInclude" - for name, case_sensitve_name in comps.items(): + for case_sensitve_name in comps.items(): ConfigurationXmlConverter._component_to_xml(root, case_sensitve_name) return minidom.parseString(ElementTree.tostring(root)).toprettyxml() @@ -544,8 +544,8 @@ def ioc_from_xml(root_xml: ElementTree.Element, iocs: OrderedDict) -> None: iocs[n.upper()].pvsets[ps.attrib[TAG_NAME]] = { TAG_ENABLED: parse_boolean(str(ps.attrib[TAG_ENABLED])) } - except Exception as err: - raise Exception("Tag not found in ioc.xml (" + str(err) + ")") + except (NodeNotPresentError, KeyError, ValueError, SyntaxError) as err: + raise ValueError("Tag not found in ioc.xml (" + str(err) + ")") @staticmethod def components_from_xml(root_xml: ElementTree.Element, components: OrderedDict) -> None: @@ -753,16 +753,14 @@ def banner_config_from_xml( banner_buttons = [] items = ConfigurationXmlConverter._find_single_node_with_none_check(root, "banner", "items") - index = 0 - for item in items: + for index, item in enumerate(items): child = item.find("./") if child is not None: if "display" in child.tag: banner_displays.append(ConfigurationXmlConverter._display(child, index)) else: banner_buttons.append(ConfigurationXmlConverter._button(child, index)) - index += 1 return { "items": banner_displays, From 5398728cd65592af428f8cdac159f4255263d368 Mon Sep 17 00:00:00 2001 From: vux62295 Date: Mon, 27 Jul 2026 14:20:19 +0100 Subject: [PATCH 19/22] More ruff fixes --- BlockServer/config/block.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BlockServer/config/block.py b/BlockServer/config/block.py index 251845af..4c8a7f61 100644 --- a/BlockServer/config/block.py +++ b/BlockServer/config/block.py @@ -14,7 +14,7 @@ # https://www.eclipse.org/org/documents/epl-v10.php or # http://opensource.org/licenses/eclipse-1.0.php -from typing import TypedDict, Union +from typing import TypedDict from server_common.helpers import PVPREFIX_MACRO From e6247fe99b7303a428c041cb8c0ecf0c7f989f34 Mon Sep 17 00:00:00 2001 From: vux62295 Date: Mon, 27 Jul 2026 14:48:47 +0100 Subject: [PATCH 20/22] More ruff fixes --- BlockServer/config/xml_converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BlockServer/config/xml_converter.py b/BlockServer/config/xml_converter.py index 7e76ec26..e9e676d0 100644 --- a/BlockServer/config/xml_converter.py +++ b/BlockServer/config/xml_converter.py @@ -187,7 +187,7 @@ def components_to_xml(comps: OrderedDict) -> str: root.attrib["xmlns"] = SCHEMA_PATH + COMPONENT_SCHEMA root.attrib["xmlns:comp"] = SCHEMA_PATH + COMPONENT_SCHEMA root.attrib["xmlns:xi"] = "http://www.w3.org/2001/XInclude" - for case_sensitve_name in comps.items(): + for _, case_sensitve_name in comps.items(): ConfigurationXmlConverter._component_to_xml(root, case_sensitve_name) return minidom.parseString(ElementTree.tostring(root)).toprettyxml() From 124ac1171a5f5a621b4b76aa303c25c2dddad86e Mon Sep 17 00:00:00 2001 From: vux62295 Date: Mon, 27 Jul 2026 15:03:24 +0100 Subject: [PATCH 21/22] More ruff fixes --- BlockServer/config/xml_converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BlockServer/config/xml_converter.py b/BlockServer/config/xml_converter.py index e9e676d0..cfd90d73 100644 --- a/BlockServer/config/xml_converter.py +++ b/BlockServer/config/xml_converter.py @@ -187,7 +187,7 @@ def components_to_xml(comps: OrderedDict) -> str: root.attrib["xmlns"] = SCHEMA_PATH + COMPONENT_SCHEMA root.attrib["xmlns:comp"] = SCHEMA_PATH + COMPONENT_SCHEMA root.attrib["xmlns:xi"] = "http://www.w3.org/2001/XInclude" - for _, case_sensitve_name in comps.items(): + for case_sensitve_name in comps.values(): ConfigurationXmlConverter._component_to_xml(root, case_sensitve_name) return minidom.parseString(ElementTree.tostring(root)).toprettyxml() From d42783ba0ac3d0b2302f32e8d1000a10a1d9a686 Mon Sep 17 00:00:00 2001 From: vux62295 Date: Mon, 27 Jul 2026 15:35:18 +0100 Subject: [PATCH 22/22] More ruff fixes --- BlockServer/config/xml_converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BlockServer/config/xml_converter.py b/BlockServer/config/xml_converter.py index cfd90d73..3884fce3 100644 --- a/BlockServer/config/xml_converter.py +++ b/BlockServer/config/xml_converter.py @@ -121,7 +121,7 @@ def blocks_to_xml(blocks: OrderedDict, macros: dict) -> str: root.attrib["xmlns"] = SCHEMA_PATH + BLOCK_SCHEMA root.attrib["xmlns:blk"] = SCHEMA_PATH + BLOCK_SCHEMA root.attrib["xmlns:xi"] = "http://www.w3.org/2001/XInclude" - for block in blocks.items(): + for block in blocks.values(): # Don't save if in component if block.component is None or block.component is False: ConfigurationXmlConverter._block_to_xml(root, block, macros)