From a9ae1af76aeef851fe5196285125dcbadb3f6955 Mon Sep 17 00:00:00 2001 From: Thibaut Vermeulen Date: Tue, 24 Oct 2023 18:12:52 +0200 Subject: [PATCH 1/3] fix leaf check when DA has Private child --- pytest.ini | 3 ++- src/scl_loader/scl_loader.py | 16 +++++++--------- .../{test_scd_manager.py => test_scl_loader.py} | 4 ++-- 3 files changed, 11 insertions(+), 12 deletions(-) rename tests/{test_scd_manager.py => test_scl_loader.py} (93%) diff --git a/pytest.ini b/pytest.ini index 5abb50b..ef19542 100644 --- a/pytest.ini +++ b/pytest.ini @@ -5,4 +5,5 @@ log_date_format = %Y-%m-%d %H:%M:%S log_cli = 1 log_cli_level = INFO log_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s) -log_cli_date_format=%Y-%m-%d %H:%M:%S \ No newline at end of file +log_cli_date_format=%Y-%m-%d %H:%M:%S +pythonpath=src diff --git a/src/scl_loader/scl_loader.py b/src/scl_loader/scl_loader.py index 8228938..7caf128 100644 --- a/src/scl_loader/scl_loader.py +++ b/src/scl_loader/scl_loader.py @@ -478,7 +478,7 @@ def get_name_subtree(self, fc_filter: str = None): for level in leaf_path.split(".")[node_depth-1:]: node = node.setdefault(level, dict()) tree_as_tuples = self._recursive_dict_to_tuple(tree) - return tree_as_tuples[0] + return tree_as_tuples[0] if len(tree_as_tuples) > 0 else [] def _recursive_dict_to_tuple(self, i_dict): """ @@ -548,24 +548,22 @@ def _create_from_etree_element(self, node_elem: etree.Element): dt_node_elem = self._datatypes.get_type_by_id(dtype_id) self._create_by_node_elem(dt_node_elem) - def _is_leaf(self, node) -> bool: + def _is_leaf(self) -> bool: """ /!\\ PRIVATE : do not use /!\\ Check if a SCDNode is leaf - Parameters - ---------- - `node` - The SCDNode to check - Returns ------- `bool` Return True if the node is leaf. """ + # return len(node.get_children()) == 0 and isinstance(node, DA) and hasattr(node, 'parent') - return len(node.get_children()) == 0 and isinstance(node, DA) and hasattr(node, 'parent') + return isinstance(self, DA) \ + and hasattr(self, 'parent') \ + and len([n for n in self.get_children() if isinstance(n, DA)]) == 0 def _collect_DA_leaf_nodes(self, node, leaves: dict) -> dict: """ @@ -587,7 +585,7 @@ def _collect_DA_leaf_nodes(self, node, leaves: dict) -> dict: The found leaves dictionnary. """ if node is not None: - if self._is_leaf(node): + if node._is_leaf(): leaves[node.get_path_from_ld()] = node else: diff --git a/tests/test_scd_manager.py b/tests/test_scl_loader.py similarity index 93% rename from tests/test_scd_manager.py rename to tests/test_scl_loader.py index 2bbe95a..19127c3 100644 --- a/tests/test_scd_manager.py +++ b/tests/test_scl_loader.py @@ -438,7 +438,7 @@ def test_IED_get_lds(self): assert len(result) == 11 assert isinstance(result[0], LD) - def test_IED_get_node_by_ref(self): + def test_IED_get_node_by_path(self): ied = self.SCD_HANDLER.get_IED_by_name('AUT1A_SITE_1') assert ied.get_node_by_path('LDASLD').name == 'LDASLD' @@ -586,7 +586,7 @@ def test_get_name_subtree(self): ln = ied.PROCESS_AP.Server.LDASLD.PTRC2 with pytest.raises(AssertionError): ied.get_name_subtree() - assert(ied.PROCESS_AP.Server.LDASLD.get_name_subtree() == ('LDASLD', [('LLN0', [('Beh', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('Health', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('InRef1', [('d', []), ('intAddr', []), ('purpose', []), ('setSrcCB', []), ('setSrcRef', []), ('setTstCB', []), ('setTstRef', []), ('tstEna', [])]), ('InRef2', [('d', []), ('intAddr', []), ('purpose', []), ('setSrcCB', []), ('setSrcRef', []), ('setTstCB', []), ('setTstRef', []), ('tstEna', [])]), ('InRef3', [('d', []), ('intAddr', []), ('purpose', []), ('setSrcCB', []), ('setSrcRef', []), ('setTstCB', []), ('setTstRef', []), ('tstEna', [])]), ('InRef4', [('d', []), ('intAddr', []), ('purpose', []), ('setSrcCB', []), ('setSrcRef', []), ('setTstCB', []), ('setTstRef', []), ('tstEna', [])]), ('InRef5', [('d', []), ('intAddr', []), ('purpose', []), ('setSrcCB', []), ('setSrcRef', []), ('setTstCB', []), ('setTstRef', []), ('tstEna', [])]), ('InRef6', [('d', []), ('intAddr', []), ('purpose', []), ('setSrcCB', []), ('setSrcRef', []), ('setTstCB', []), ('setTstRef', []), ('tstEna', [])]), ('InRef7', [('d', []), ('intAddr', []), ('purpose', []), ('setSrcCB', []), ('setSrcRef', []), ('setTstCB', []), ('setTstRef', []), ('tstEna', [])]), ('Mod', [('ctlModel', []), ('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('NamPlt', [('ldNs', []), ('d', []), ('paramRev', []), ('valRev', []), ('vendor', [])])]), ('RBRF2', [('Beh', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('OpEx', [('d', []), ('general', []), ('neut', []), ('phsA', []), ('phsB', []), ('phsC', []), ('q', []), ('t', []), ('originSrc', [('orCat', []), ('orIdent', [])])])]), ('RBRF1', [('Beh', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('OpEx', [('d', []), ('general', []), ('neut', []), ('phsA', []), ('phsB', []), ('phsC', []), ('q', []), ('t', []), ('originSrc', [('orCat', []), ('orIdent', [])])])]), ('PTRC2', [('Beh', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('Tr', [('d', []), ('general', []), ('neut', []), ('phsA', []), ('phsB', []), ('phsC', []), ('q', []), ('t', []), ('originSrc', [('orCat', []), ('orIdent', [])])])]), ('PTRC1', [('Beh', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('Tr', [('d', []), ('general', []), ('neut', []), ('phsA', []), ('phsB', []), ('phsC', []), ('q', []), ('t', []), ('originSrc', [('orCat', []), ('orIdent', [])])])]), ('RBRF3', [('Beh', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('OpEx', [('d', []), ('general', []), ('neut', []), ('phsA', []), ('phsB', []), ('phsC', []), ('q', []), ('t', []), ('originSrc', [('orCat', []), ('orIdent', [])])])]), ('LPHD0', [('NamPlt', [('configRev', []), ('d', []), ('paramRev', []), ('swRev', []), ('valRev', []), ('vendor', [])]), ('PhyHealth', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('PhyNam', [('d', []), ('hwRev', []), ('location', []), ('mRID', []), ('model', []), ('serNum', []), ('swRev', []), ('vendor', [])]), ('Proxy', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])])]), ('PTRC3', [('Beh', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('Tr', [('d', []), ('general', []), ('neut', []), ('phsA', []), ('phsB', []), ('phsC', []), ('q', []), ('t', []), ('originSrc', [('orCat', []), ('orIdent', [])])])])])) + assert(ied.PROCESS_AP.Server.LDASLD.get_name_subtree() == ('LDASLD', [('LLN0', [('Beh', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('Health', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('InRef1', [('d', []), ('intAddr', []), ('purpose', []), ('setSrcCB', []), ('setSrcRef', []), ('setTstCB', []), ('setTstRef', []), ('tstEna', [])]), ('InRef2', [('d', []), ('intAddr', []), ('purpose', []), ('setSrcCB', []), ('setSrcRef', []), ('setTstCB', []), ('setTstRef', []), ('tstEna', [])]), ('InRef3', [('d', []), ('intAddr', []), ('purpose', []), ('setSrcCB', []), ('setSrcRef', []), ('setTstCB', []), ('setTstRef', []), ('tstEna', [])]), ('InRef4', [('d', []), ('intAddr', []), ('purpose', []), ('setSrcCB', []), ('setSrcRef', []), ('setTstCB', []), ('setTstRef', []), ('tstEna', [])]), ('InRef5', [('d', []), ('intAddr', []), ('purpose', []), ('setSrcCB', []), ('setSrcRef', []), ('setTstCB', []), ('setTstRef', []), ('tstEna', [])]), ('InRef6', [('d', []), ('intAddr', []), ('purpose', []), ('setSrcCB', []), ('setSrcRef', []), ('setTstCB', []), ('setTstRef', []), ('tstEna', [])]), ('InRef7', [('d', []), ('intAddr', []), ('purpose', []), ('setSrcCB', []), ('setSrcRef', []), ('setTstCB', []), ('setTstRef', []), ('tstEna', [])]), ('Mod', [('ctlModel', []), ('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('NamPlt', [('ldNs', []), ('configRev', []), ('d', []), ('paramRev', []), ('swRev', []), ('valRev', []), ('vendor', [])])]), ('RBRF2', [('Beh', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('OpEx', [('d', []), ('general', []), ('neut', []), ('phsA', []), ('phsB', []), ('phsC', []), ('q', []), ('t', []), ('originSrc', [('orCat', []), ('orIdent', [])])])]), ('RBRF1', [('Beh', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('OpEx', [('d', []), ('general', []), ('neut', []), ('phsA', []), ('phsB', []), ('phsC', []), ('q', []), ('t', []), ('originSrc', [('orCat', []), ('orIdent', [])])])]), ('PTRC2', [('Beh', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('Tr', [('d', []), ('general', []), ('neut', []), ('phsA', []), ('phsB', []), ('phsC', []), ('q', []), ('t', []), ('originSrc', [('orCat', []), ('orIdent', [])])])]), ('PTRC1', [('Beh', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('Tr', [('d', []), ('general', []), ('neut', []), ('phsA', []), ('phsB', []), ('phsC', []), ('q', []), ('t', []), ('originSrc', [('orCat', []), ('orIdent', [])])])]), ('RBRF3', [('Beh', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('OpEx', [('d', []), ('general', []), ('neut', []), ('phsA', []), ('phsB', []), ('phsC', []), ('q', []), ('t', []), ('originSrc', [('orCat', []), ('orIdent', [])])])]), ('LPHD0', [('NamPlt', [('configRev', []), ('d', []), ('paramRev', []), ('swRev', []), ('valRev', []), ('vendor', [])]), ('PhyHealth', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('PhyNam', [('d', []), ('hwRev', []), ('location', []), ('mRID', []), ('model', []), ('serNum', []), ('swRev', []), ('vendor', [])]), ('Proxy', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])])]), ('PTRC3', [('Beh', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('Tr', [('d', []), ('general', []), ('neut', []), ('phsA', []), ('phsB', []), ('phsC', []), ('q', []), ('t', []), ('originSrc', [('orCat', []), ('orIdent', [])])])])])) assert(ln.get_name_subtree() == ('PTRC2', [('Beh', [('blkEna', []), ('d', []), ('q', []), ('stVal', []), ('subEna', []), ('subID', []), ('subQ', []), ('subVal', []), ('t', [])]), ('Tr', [('d', []), ('general', []), ('neut', []), ('phsA', []), ('phsB', []), ('phsC', []), ('q', []), ('t', []), ('originSrc', [('orCat', []), ('orIdent', [])])])])) assert(ln.Tr.d.get_name_subtree() == ('d', []) ) assert(ln.Tr.get_name_subtree() == ('Tr', [('d', []), ('general', []), ('neut', []), ('phsA', []), ('phsB', []), ('phsC', []), ('q', []), ('t', []), ('originSrc', [('orCat', []), ('orIdent', [])])])) From 950eb0760d9d47c78319e9c49b8ce8d25e1c6808 Mon Sep 17 00:00:00 2001 From: Thibaut Vermeulen Date: Wed, 25 Oct 2023 09:30:34 +0200 Subject: [PATCH 2/3] update version to 1.11.3 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index f49f7d6..b4c2fed 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ # Fields marked as "Optional" may be commented out. setup( name='scl_loader', # Required - version='1.11.2', # Required + version='1.11.3', # Required description='Outil de manipulation de SCD', # Required long_description=LONG_DESCRIPTION, # Optional long_description_content_type='text/markdown', # Optional (see note above) From 5a86a02fbc0f3c5e5699c9fccbc67b55c1104093 Mon Sep 17 00:00:00 2001 From: Thibaut Vermeulen Date: Wed, 25 Oct 2023 09:37:59 +0200 Subject: [PATCH 3/3] cleaning --- src/scl_loader/scl_loader.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/scl_loader/scl_loader.py b/src/scl_loader/scl_loader.py index 7caf128..ced1080 100644 --- a/src/scl_loader/scl_loader.py +++ b/src/scl_loader/scl_loader.py @@ -559,11 +559,9 @@ def _is_leaf(self) -> bool: `bool` Return True if the node is leaf. """ - # return len(node.get_children()) == 0 and isinstance(node, DA) and hasattr(node, 'parent') - return isinstance(self, DA) \ and hasattr(self, 'parent') \ - and len([n for n in self.get_children() if isinstance(n, DA)]) == 0 + and not any(isinstance(n, DA) for n in self.get_children()) def _collect_DA_leaf_nodes(self, node, leaves: dict) -> dict: """