From 3ab18dcf3ed5642d64ecfd69d1b83badcb785758 Mon Sep 17 00:00:00 2001 From: Xavier Sosnovsky Date: Thu, 22 Feb 2024 14:10:01 +0100 Subject: [PATCH 1/4] Retrieve hierarchy codes as a flat list --- src/pysdmx/model/code.py | 23 +++++++++++++++++++++++ tests/model/test_hierarchy.py | 23 +++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/pysdmx/model/code.py b/src/pysdmx/model/code.py index e13ed5b..0d9c446 100644 --- a/src/pysdmx/model/code.py +++ b/src/pysdmx/model/code.py @@ -257,6 +257,29 @@ def by_id(self, id: str) -> Sequence[HierarchicalCode]: """ return self.__by_id(id, self.codes) + def __get_codes(self, codes: Sequence[HierarchicalCode]): + out = [] + for code in codes: + out.append(code) + if code.codes: + out.extend(self.__get_codes(code.codes)) + return out + + def all_codes(self) -> Sequence[HierarchicalCode]: + """Get all the codes in the hierarchy as a flat list. + + This is useful for validation purposes. The sequence behaves + as a set, i.e. even if a code is attached to multiple nodes, + it will be available only once in the returned sequence. + """ + out = [] + # We need to do this below because a hierarchical code is not + # (yet?) hashable. + for c in self.__get_codes(self.codes): + if c not in out: + out.append(c) + return out + class HierarchyAssociation(Struct, frozen=True, omit_defaults=True): """Links a hierarchy to a component withing the context of a dataflow.""" diff --git a/tests/model/test_hierarchy.py b/tests/model/test_hierarchy.py index f941857..8aad1e8 100644 --- a/tests/model/test_hierarchy.py +++ b/tests/model/test_hierarchy.py @@ -169,3 +169,26 @@ def test_codes_by_id_diff_names(id, name, agency): m = list(m) assert grandchild1 in m assert grandchild3 in m + + +def test_all_codes(id, name, agency): + grandchild1 = HierarchicalCode("grandchild1", "grandchild 1") + grandchild2 = HierarchicalCode("grandchild2", "grandchild 2") + grandchild3 = HierarchicalCode("grandchild3", "grandchild 3") + child1 = HierarchicalCode( + "child1", "child 1", codes=[grandchild1, grandchild2] + ) + child2 = HierarchicalCode( + "child2", "child 2", codes=[grandchild1, grandchild2, grandchild3] + ) + parent1 = HierarchicalCode("parent1", "parent 1") + parent2 = HierarchicalCode( + "parent2", + "parent 2", + codes=[child1, child2], + ) + + h = Hierarchy(id, name, agency, codes=[parent1, parent2]) + + m = h.all_codes() + assert len(m) == 7 From 8985220f14d2733381b4a750180534521357a3b9 Mon Sep 17 00:00:00 2001 From: Xavier Sosnovsky Date: Thu, 22 Feb 2024 14:10:42 +0100 Subject: [PATCH 2/4] Bump version --- pyproject.toml | 2 +- src/pysdmx/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 68ebdd8..f2dbd09 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "pysdmx" -version = "1.0.0-beta-7" +version = "1.0.0-beta-8" description = "Your opinionated Python SDMX library" authors = [ "Xavier Sosnovsky ", diff --git a/src/pysdmx/__init__.py b/src/pysdmx/__init__.py index 774c2bf..5773f50 100644 --- a/src/pysdmx/__init__.py +++ b/src/pysdmx/__init__.py @@ -1,3 +1,3 @@ """Your opinionated Python SDMX library.""" -__version__ = "1.0.0-beta-7" +__version__ = "1.0.0-beta-8" From b4b565dace62e6542efbdd47768f18fa033da7bc Mon Sep 17 00:00:00 2001 From: Xavier Sosnovsky Date: Thu, 22 Feb 2024 14:18:21 +0100 Subject: [PATCH 3/4] Fix QA issues --- src/pysdmx/model/code.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pysdmx/model/code.py b/src/pysdmx/model/code.py index 0d9c446..4cf85ea 100644 --- a/src/pysdmx/model/code.py +++ b/src/pysdmx/model/code.py @@ -257,7 +257,9 @@ def by_id(self, id: str) -> Sequence[HierarchicalCode]: """ return self.__by_id(id, self.codes) - def __get_codes(self, codes: Sequence[HierarchicalCode]): + def __get_codes( + self, codes: Sequence[HierarchicalCode] + ) -> Sequence[HierarchicalCode]: out = [] for code in codes: out.append(code) @@ -271,6 +273,9 @@ def all_codes(self) -> Sequence[HierarchicalCode]: This is useful for validation purposes. The sequence behaves as a set, i.e. even if a code is attached to multiple nodes, it will be available only once in the returned sequence. + + Returns: + A flat list of the codes present in the hierarchy. """ out = [] # We need to do this below because a hierarchical code is not From bad92814408de4ebd78a0ced14b0cd6030f8cbc4 Mon Sep 17 00:00:00 2001 From: Xavier Sosnovsky Date: Thu, 22 Feb 2024 14:37:04 +0100 Subject: [PATCH 4/4] Avoid duplicated strings --- src/pysdmx/util/__init__.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/pysdmx/util/__init__.py b/src/pysdmx/util/__init__.py index 2c3397c..732645d 100644 --- a/src/pysdmx/util/__init__.py +++ b/src/pysdmx/util/__init__.py @@ -7,6 +7,8 @@ from pysdmx.errors import NotFound +NF = "Not found" + class Reference(Struct, frozen=True): """The coordinates of an SDMX maintainable artefact. @@ -58,9 +60,7 @@ def parse_urn(urn: str) -> Reference: ) else: raise NotFound( - 404, - "Not found", - f"{urn} does not match {maintainable_urn_pattern}", + 404, NF, f"{urn} does not match {maintainable_urn_pattern}" ) @@ -76,9 +76,7 @@ def parse_item_urn(urn: str) -> ItemReference: item_id=m.group(5), ) else: - raise NotFound( - 404, "Not found", f"{urn} does not match {item_urn_pattern}." - ) + raise NotFound(404, NF, f"{urn} does not match {item_urn_pattern}.") def find_by_urn(artefacts: Sequence[Any], urn: str) -> Any: @@ -95,7 +93,7 @@ def find_by_urn(artefacts: Sequence[Any], urn: str) -> Any: urns = [f"{a.agency}:{a.id}({a.version})" for a in artefacts] raise NotFound( 404, - "Not found", + NF, ( f"Could not find an artefact matching the following URN: " f"{urn}. The artefacts received were: {urns}."