From e0a6ba651a34431946eb1f579808b280761040eb Mon Sep 17 00:00:00 2001 From: Rezwan Matin Date: Wed, 27 Aug 2025 16:41:01 -0400 Subject: [PATCH 01/13] Added a function for parsing AllowedValues --- birdy/client/utils.py | 47 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/birdy/client/utils.py b/birdy/client/utils.py index b98a93d..69614dd 100644 --- a/birdy/client/utils.py +++ b/birdy/client/utils.py @@ -142,7 +142,7 @@ def build_process_doc(process: Process) -> str: doc.append("Parameters") doc.append("----------") for i in process.dataInputs: - doc.append(f"{sanitize(i.identifier)} : {format_type(i)}") + doc.append(f"{sanitize(i.identifier)} : {format_allowed_values(process, i.identifier)}") doc.append(f" {i.abstract or i.title}") # if i.metadata: # doc[-1] += " ({})".format(', '.join(['`{} <{}>`_'.format(m.title, m.href) for m in i.metadata])) @@ -160,6 +160,45 @@ def build_process_doc(process: Process) -> str: return "\n".join(doc) +def format_allowed_values(process: Process, input_id: str) -> str: + """ + Parse AllowedValues manually from raw XML for the given Process and Input. + + Parameters + ---------- + process : owslib.wps.Process + A WPS process. + input_id: str + An Input identifier. + + Returns + ------- + str + The AllowedValues for the given Input. + """ + root = process._xml + nmax = 10 + doc = "" + for input_elem in process.xpath("DataInputs/Input"): + if input_elem.find("ows:Identifier", namespaces=ns).text == input_id: + if input_elem.find(".//ows:AllowedValues", namespaces=ns) is not None: + if input_elem.find(".//ows:Range", namespaces=ns) is not None: + min_val = input_elem.find(".//ows:MinimumValue", namespaces=ns).text + max_val = input_elem.find(".//ows:MaximumValue", namespaces=ns).text + doc += "{" + f"'{min_val}'" + "->" + f"'{max_val}'" + "}" + else: + values = input_elem.xpath(".//ows:Value", namespaces=ns) + allowed = [v.text for v in values] + av = ", ".join([f"'{i}'" for i in allowed[:nmax]]) + if len(allowed) > nmax: + av += ", ..." + doc += "{" + av + "}" + else: + doc += "{" + f"'{None}'" + "}" + break + return doc + + def format_type(obj: Any) -> str: """ Create docstring entry for input parameter from an OWSlib object. @@ -178,12 +217,6 @@ def format_type(obj: Any) -> str: doc = "" try: - if getattr(obj, "allowedValues", None): - av = ", ".join([f"'{i}'" for i in obj.allowedValues[:nmax]]) - if len(obj.allowedValues) > nmax: - av += ", ..." - doc += "{" + av + "}" - if getattr(obj, "dataType", None): doc += obj.dataType From 7937accf1b3064aed28b9ba054707a2b9e00dcb8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 27 Aug 2025 20:58:06 +0000 Subject: [PATCH 02/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- birdy/client/utils.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/birdy/client/utils.py b/birdy/client/utils.py index 69614dd..ca6e584 100644 --- a/birdy/client/utils.py +++ b/birdy/client/utils.py @@ -142,7 +142,9 @@ def build_process_doc(process: Process) -> str: doc.append("Parameters") doc.append("----------") for i in process.dataInputs: - doc.append(f"{sanitize(i.identifier)} : {format_allowed_values(process, i.identifier)}") + doc.append( + f"{sanitize(i.identifier)} : {format_allowed_values(process, i.identifier)}" + ) doc.append(f" {i.abstract or i.title}") # if i.metadata: # doc[-1] += " ({})".format(', '.join(['`{} <{}>`_'.format(m.title, m.href) for m in i.metadata])) @@ -168,19 +170,19 @@ def format_allowed_values(process: Process, input_id: str) -> str: ---------- process : owslib.wps.Process A WPS process. - input_id: str - An Input identifier. + input_id: str + An Input identifier. Returns ------- str The AllowedValues for the given Input. """ - root = process._xml + root = process._xml nmax = 10 doc = "" for input_elem in process.xpath("DataInputs/Input"): - if input_elem.find("ows:Identifier", namespaces=ns).text == input_id: + if input_elem.find("ows:Identifier", namespaces=ns).text == input_id: if input_elem.find(".//ows:AllowedValues", namespaces=ns) is not None: if input_elem.find(".//ows:Range", namespaces=ns) is not None: min_val = input_elem.find(".//ows:MinimumValue", namespaces=ns).text From 5b584d82f0f565df212f957760fb8b3aaec0a5e9 Mon Sep 17 00:00:00 2001 From: Rezwan Matin Date: Wed, 27 Aug 2025 22:30:02 -0400 Subject: [PATCH 03/13] Consolidated formatted input strings --- birdy/client/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/birdy/client/utils.py b/birdy/client/utils.py index ca6e584..b2d019d 100644 --- a/birdy/client/utils.py +++ b/birdy/client/utils.py @@ -143,7 +143,7 @@ def build_process_doc(process: Process) -> str: doc.append("----------") for i in process.dataInputs: doc.append( - f"{sanitize(i.identifier)} : {format_allowed_values(process, i.identifier)}" + f"{sanitize(i.identifier)} : {format_allowed_values(process, i.identifier) + format_type(i)}" ) doc.append(f" {i.abstract or i.title}") # if i.metadata: From 1d59a72408632f360c245d16ea41694299fc1a08 Mon Sep 17 00:00:00 2001 From: Rezwan Matin Date: Thu, 28 Aug 2025 15:34:58 -0400 Subject: [PATCH 04/13] Fixed formatting, added missing variables, and removed unused variables --- birdy/client/utils.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/birdy/client/utils.py b/birdy/client/utils.py index b2d019d..40cff24 100644 --- a/birdy/client/utils.py +++ b/birdy/client/utils.py @@ -143,7 +143,7 @@ def build_process_doc(process: Process) -> str: doc.append("----------") for i in process.dataInputs: doc.append( - f"{sanitize(i.identifier)} : {format_allowed_values(process, i.identifier) + format_type(i)}" + f"{sanitize(i.identifier)} : {format_allowed_values(process, i.identifier)}{format_type(i)}" ) doc.append(f" {i.abstract or i.title}") # if i.metadata: @@ -170,7 +170,7 @@ def format_allowed_values(process: Process, input_id: str) -> str: ---------- process : owslib.wps.Process A WPS process. - input_id: str + input_id : str An Input identifier. Returns @@ -178,9 +178,11 @@ def format_allowed_values(process: Process, input_id: str) -> str: str The AllowedValues for the given Input. """ - root = process._xml nmax = 10 doc = "" + ns = {"wps": "http://www.opengis.net/wps/1.0.0", + "ows": "http://www.opengis.net/ows/1.1", + } for input_elem in process.xpath("DataInputs/Input"): if input_elem.find("ows:Identifier", namespaces=ns).text == input_id: if input_elem.find(".//ows:AllowedValues", namespaces=ns) is not None: From 46fde4645dd266efa7f0969a1ce8c6ab52a746fe Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 28 Aug 2025 19:35:27 +0000 Subject: [PATCH 05/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- birdy/client/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/birdy/client/utils.py b/birdy/client/utils.py index 40cff24..fd07dda 100644 --- a/birdy/client/utils.py +++ b/birdy/client/utils.py @@ -180,8 +180,9 @@ def format_allowed_values(process: Process, input_id: str) -> str: """ nmax = 10 doc = "" - ns = {"wps": "http://www.opengis.net/wps/1.0.0", - "ows": "http://www.opengis.net/ows/1.1", + ns = { + "wps": "http://www.opengis.net/wps/1.0.0", + "ows": "http://www.opengis.net/ows/1.1", } for input_elem in process.xpath("DataInputs/Input"): if input_elem.find("ows:Identifier", namespaces=ns).text == input_id: From ac397351c06fb23fdcae5818fcf89d83f04d0a8b Mon Sep 17 00:00:00 2001 From: Rezwan Matin Date: Thu, 28 Aug 2025 16:08:52 -0400 Subject: [PATCH 06/13] Fixed issue by converting OWSLib Process object into lxml.etree._Element --- birdy/client/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/birdy/client/utils.py b/birdy/client/utils.py index fd07dda..9f7174b 100644 --- a/birdy/client/utils.py +++ b/birdy/client/utils.py @@ -180,11 +180,11 @@ def format_allowed_values(process: Process, input_id: str) -> str: """ nmax = 10 doc = "" - ns = { - "wps": "http://www.opengis.net/wps/1.0.0", - "ows": "http://www.opengis.net/ows/1.1", + ns = {"wps": "http://www.opengis.net/wps/1.0.0", + "ows": "http://www.opengis.net/ows/1.1", } - for input_elem in process.xpath("DataInputs/Input"): + xml_tree = process._processDescription + for input_elem in xml_tree.xpath("DataInputs/Input"): if input_elem.find("ows:Identifier", namespaces=ns).text == input_id: if input_elem.find(".//ows:AllowedValues", namespaces=ns) is not None: if input_elem.find(".//ows:Range", namespaces=ns) is not None: From a4cd9a059ecccfb6e396d64daf8270307b6262bb Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 28 Aug 2025 20:09:31 +0000 Subject: [PATCH 07/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- birdy/client/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/birdy/client/utils.py b/birdy/client/utils.py index 9f7174b..25e2cb1 100644 --- a/birdy/client/utils.py +++ b/birdy/client/utils.py @@ -180,8 +180,9 @@ def format_allowed_values(process: Process, input_id: str) -> str: """ nmax = 10 doc = "" - ns = {"wps": "http://www.opengis.net/wps/1.0.0", - "ows": "http://www.opengis.net/ows/1.1", + ns = { + "wps": "http://www.opengis.net/wps/1.0.0", + "ows": "http://www.opengis.net/ows/1.1", } xml_tree = process._processDescription for input_elem in xml_tree.xpath("DataInputs/Input"): From 9d4ccdc251686c4f9b42272e94d99f97133c1e55 Mon Sep 17 00:00:00 2001 From: Rezwan Matin Date: Wed, 3 Sep 2025 09:32:53 -0400 Subject: [PATCH 08/13] Add WPS Service as input to build_process_doc --- birdy/client/base.py | 2 +- birdy/client/utils.py | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/birdy/client/base.py b/birdy/client/base.py index 9e83422..9605c8f 100644 --- a/birdy/client/base.py +++ b/birdy/client/base.py @@ -284,7 +284,7 @@ def _method_factory(self, pid: str) -> Callable: func_builder = FunctionBuilder( name=sanitize(pid), - doc=utils.build_process_doc(process), + doc=utils.build_process_doc(self._wps, process), args=["self"] + input_names, defaults=defaults, body=body, diff --git a/birdy/client/utils.py b/birdy/client/utils.py index 25e2cb1..a9317fa 100644 --- a/birdy/client/utils.py +++ b/birdy/client/utils.py @@ -121,12 +121,14 @@ def build_wps_client_doc( return "\n".join(doc) -def build_process_doc(process: Process) -> str: +def build_process_doc(wps: WebProcessingService, process: Process) -> str: """ Create docstring from process metadata. Parameters ---------- + wps : owslib.wps.WebProcessingService + A WPS service. process : owslib.wps.Process A WPS process. @@ -136,6 +138,7 @@ def build_process_doc(process: Process) -> str: The formatted docstring for this process. """ doc = [process.abstract or "", ""] + _process = wps.describeprocess(process.identifier) # Inputs if process.dataInputs: @@ -143,7 +146,7 @@ def build_process_doc(process: Process) -> str: doc.append("----------") for i in process.dataInputs: doc.append( - f"{sanitize(i.identifier)} : {format_allowed_values(process, i.identifier)}{format_type(i)}" + f"{sanitize(i.identifier)} : {format_allowed_values(_process, i.identifier)}{format_type(i)}" ) doc.append(f" {i.abstract or i.title}") # if i.metadata: @@ -180,9 +183,8 @@ def format_allowed_values(process: Process, input_id: str) -> str: """ nmax = 10 doc = "" - ns = { - "wps": "http://www.opengis.net/wps/1.0.0", - "ows": "http://www.opengis.net/ows/1.1", + ns = {"wps": "http://www.opengis.net/wps/1.0.0", + "ows": "http://www.opengis.net/ows/1.1", } xml_tree = process._processDescription for input_elem in xml_tree.xpath("DataInputs/Input"): From 0359645d433c1db02c7c3331028c41ef90065332 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 3 Sep 2025 13:33:58 +0000 Subject: [PATCH 09/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- birdy/client/utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/birdy/client/utils.py b/birdy/client/utils.py index a9317fa..aa2e609 100644 --- a/birdy/client/utils.py +++ b/birdy/client/utils.py @@ -183,8 +183,9 @@ def format_allowed_values(process: Process, input_id: str) -> str: """ nmax = 10 doc = "" - ns = {"wps": "http://www.opengis.net/wps/1.0.0", - "ows": "http://www.opengis.net/ows/1.1", + ns = { + "wps": "http://www.opengis.net/wps/1.0.0", + "ows": "http://www.opengis.net/ows/1.1", } xml_tree = process._processDescription for input_elem in xml_tree.xpath("DataInputs/Input"): From 0167a5012d5326e1688d4c22e432e99abb82ac03 Mon Sep 17 00:00:00 2001 From: Rezwan Matin Date: Mon, 8 Sep 2025 11:17:03 -0400 Subject: [PATCH 10/13] Added unit test for checking the order of AllowedValues --- birdy/client/utils.py | 9 ++++++--- tests/test_client.py | 9 ++++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/birdy/client/utils.py b/birdy/client/utils.py index aa2e609..6e3b737 100644 --- a/birdy/client/utils.py +++ b/birdy/client/utils.py @@ -192,9 +192,12 @@ def format_allowed_values(process: Process, input_id: str) -> str: if input_elem.find("ows:Identifier", namespaces=ns).text == input_id: if input_elem.find(".//ows:AllowedValues", namespaces=ns) is not None: if input_elem.find(".//ows:Range", namespaces=ns) is not None: - min_val = input_elem.find(".//ows:MinimumValue", namespaces=ns).text - max_val = input_elem.find(".//ows:MaximumValue", namespaces=ns).text - doc += "{" + f"'{min_val}'" + "->" + f"'{max_val}'" + "}" + ranges = process.xpath(".//ows:Range", namespaces=ns) + for r in ranges: + min_val = r.find(".//ows:MinimumValue", namespaces=ns).text + max_val = r.find(".//ows:MaximumValue", namespaces=ns).text + spacing = r.find(".//ows:Spacing", namespaces=ns).text if r.find(".//ows:Spacing", namespaces=ns) is not None else 1 + doc += "{" + f"'{min_val}'" + "->" + f"'{max_val}'" + f" steps: '{spacing}'" + "}" else: values = input_elem.xpath(".//ows:Value", namespaces=ns) allowed = [v.text for v in values] diff --git a/tests/test_client.py b/tests/test_client.py index 8c6e389..64c50b5 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -12,7 +12,7 @@ from birdy import WPSClient from birdy.client import nb_form from birdy.client.base import sort_inputs_key -from birdy.client.utils import is_embedded_in_request +from birdy.client.utils import is_embedded_in_request, format_allowed_values # 52 north WPS url_52n = "http://geoprocessing.demo.52north.org:8080/wps/WebProcessingService?service=WPS&version=1.0.0&request=GetCapabilities" # noqa: E501 @@ -45,6 +45,13 @@ def test_wps_supported_languages(wps_offline): # noqa: D103 assert wps_offline.languages.supported == ["en-US", "fr-CA"] +def test_method_factory(wps_offline): + """Check the order of AllowedValues in the docstring of a WPSClient instance's method.""" + func_doc = wps_offline._method_factory(pid="inout").__doc__ + assert "{'rock', 'paper', 'scissor'}" in func_doc + assert "{'1'->'10' steps: '1'}{'100'->'200' steps: '10'}" in func_doc + + @pytest.mark.online def test_wps_with_language_arg(): # noqa: D103 wps = WPSClient(URL_EMU, language="fr-CA") From a3b613f96d53706167ab62148f9dcd52147d3ced Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 8 Sep 2025 15:17:41 +0000 Subject: [PATCH 11/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- birdy/client/utils.py | 15 +++++++++++++-- tests/test_client.py | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/birdy/client/utils.py b/birdy/client/utils.py index 6e3b737..ff3f547 100644 --- a/birdy/client/utils.py +++ b/birdy/client/utils.py @@ -196,8 +196,19 @@ def format_allowed_values(process: Process, input_id: str) -> str: for r in ranges: min_val = r.find(".//ows:MinimumValue", namespaces=ns).text max_val = r.find(".//ows:MaximumValue", namespaces=ns).text - spacing = r.find(".//ows:Spacing", namespaces=ns).text if r.find(".//ows:Spacing", namespaces=ns) is not None else 1 - doc += "{" + f"'{min_val}'" + "->" + f"'{max_val}'" + f" steps: '{spacing}'" + "}" + spacing = ( + r.find(".//ows:Spacing", namespaces=ns).text + if r.find(".//ows:Spacing", namespaces=ns) is not None + else 1 + ) + doc += ( + "{" + + f"'{min_val}'" + + "->" + + f"'{max_val}'" + + f" steps: '{spacing}'" + + "}" + ) else: values = input_elem.xpath(".//ows:Value", namespaces=ns) allowed = [v.text for v in values] diff --git a/tests/test_client.py b/tests/test_client.py index 64c50b5..3610930 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -12,7 +12,7 @@ from birdy import WPSClient from birdy.client import nb_form from birdy.client.base import sort_inputs_key -from birdy.client.utils import is_embedded_in_request, format_allowed_values +from birdy.client.utils import format_allowed_values, is_embedded_in_request # 52 north WPS url_52n = "http://geoprocessing.demo.52north.org:8080/wps/WebProcessingService?service=WPS&version=1.0.0&request=GetCapabilities" # noqa: E501 From 648f675746fdddc0624b145ca734ebce8a4e6f21 Mon Sep 17 00:00:00 2001 From: Rezwan Matin Date: Mon, 8 Sep 2025 11:39:20 -0400 Subject: [PATCH 12/13] Removed redundant code --- tests/test_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_client.py b/tests/test_client.py index 3610930..6a1ebac 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -12,7 +12,7 @@ from birdy import WPSClient from birdy.client import nb_form from birdy.client.base import sort_inputs_key -from birdy.client.utils import format_allowed_values, is_embedded_in_request +from birdy.client.utils import is_embedded_in_request # 52 north WPS url_52n = "http://geoprocessing.demo.52north.org:8080/wps/WebProcessingService?service=WPS&version=1.0.0&request=GetCapabilities" # noqa: E501 From 545415874a641dc97fb667a782b6f2046971e6e2 Mon Sep 17 00:00:00 2001 From: Rezwan Matin Date: Mon, 8 Sep 2025 14:25:58 -0400 Subject: [PATCH 13/13] Added another check in unit test. --- tests/test_client.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_client.py b/tests/test_client.py index 6a1ebac..a2cbda6 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -48,6 +48,7 @@ def test_wps_supported_languages(wps_offline): # noqa: D103 def test_method_factory(wps_offline): """Check the order of AllowedValues in the docstring of a WPSClient instance's method.""" func_doc = wps_offline._method_factory(pid="inout").__doc__ + assert "{'1', '2', '3', '5', '7', '11'}" in func_doc assert "{'rock', 'paper', 'scissor'}" in func_doc assert "{'1'->'10' steps: '1'}{'100'->'200' steps: '10'}" in func_doc