From a16b20bc2e0834298d12a03135d1bd2515a8bce2 Mon Sep 17 00:00:00 2001 From: Francis Charette Migneault Date: Fri, 15 Sep 2023 18:29:09 -0400 Subject: [PATCH 1/5] add CLI package operation + support CWL package retrieval for provider process --- CHANGES.rst | 4 +- weaver/cli.py | 87 +++++++++++++++++++++-- weaver/wps_restapi/providers/__init__.py | 3 + weaver/wps_restapi/providers/providers.py | 24 +++++-- weaver/wps_restapi/swagger_definitions.py | 9 +++ 5 files changed, 117 insertions(+), 10 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 8bd04e26e..cc11fa570 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -12,7 +12,9 @@ Changes Changes: -------- -- No change. +- Add ``GET /providers/{provider_id}/processes/{process_id}/package`` endpoint that allows retrieval of the `CWL` + `Application Package` definition generated for the specific `Provider`'s `Process` definition. +- Add `CLI` ``package`` operation to request the remote `Provider` or local `Process` `CWL` `Application Package`. Fixes: ------ diff --git a/weaver/cli.py b/weaver/cli.py index a908da28c..19174a775 100644 --- a/weaver/cli.py +++ b/weaver/cli.py @@ -7,6 +7,7 @@ import os import re import sys +import textwrap import time from typing import TYPE_CHECKING from urllib.parse import urlparse @@ -14,6 +15,7 @@ import yaml from pyramid.httpexceptions import HTTPNotImplemented from requests.auth import AuthBase, HTTPBasicAuth +from requests.sessions import Session from requests.structures import CaseInsensitiveDict from webob.headers import ResponseHeaders from yaml.scanner import ScannerError @@ -22,7 +24,7 @@ from weaver.datatype import AutoBase from weaver.exceptions import PackageRegistrationError from weaver.execute import ExecuteMode, ExecuteResponse, ExecuteTransmissionMode -from weaver.formats import ContentType, OutputFormat, get_content_type, get_format +from weaver.formats import ContentType, OutputFormat, get_content_type, get_format, repr_json from weaver.processes.constants import ProcessSchema from weaver.processes.convert import ( convert_input_values_schema, @@ -348,7 +350,6 @@ def __init__(self, url=None, auth=None): def _request(self, method, # type: AnyRequestMethod url, # type: str - *args, # type: Any headers=None, # type: Optional[AnyHeadersContainer] x_headers=None, # type: Optional[AnyHeadersContainer] request_timeout=None, # type: Optional[int] @@ -370,7 +371,20 @@ def _request(self, if isinstance(request_retries, int) and request_retries > 0: kwargs.setdefault("retries", request_retries) - return request_extra(method, url, *args, headers=headers, **kwargs) + if LOGGER.isEnabledFor(logging.DEBUG): + fields = set(inspect.signature(Session.request).parameters) - {"params", "url", "method", "json", "body"} + options = {opt: val for opt, val in kwargs.items() if opt in fields} + tab = " " + LOGGER.debug( + f"Request:\n{tab}%s %s\n{tab}Queries:\n%s\n{tab}Headers:\n%s\n{tab}Content:\n%s\n{tab}Options:\n%s", + method, + url, + textwrap.indent(repr_json(kwargs.get("params") or {}, indent=len(tab)), tab * 2), + textwrap.indent(repr_json(headers or {}, indent=len(tab)), tab * 2), + textwrap.indent(repr_json(kwargs.get("json") or kwargs.get("body") or {}, indent=len(tab)), tab * 2), + textwrap.indent(repr_json(options, indent=len(tab)), tab * 2), + ) + return request_extra(method, url, headers=headers, **kwargs) def _get_url(self, url): # type: (Optional[str]) -> str @@ -538,6 +552,9 @@ def register(self, """ Registers a remote :term:`Provider` using specified references. + .. note:: + This operation is specific to `Weaver`. It is not supported by standard :term:`OGC API - Processes`. + :param provider_id: Identifier to employ for registering the new :term:`Provider`. :param provider_url: Endpoint location to register the new remote :term:`Provider`. :param url: Instance URL if not already provided during client creation. @@ -576,6 +593,9 @@ def unregister(self, """ Unregisters a remote :term:`Provider` using the specified identifier. + .. note:: + This operation is specific to `Weaver`. It is not supported by standard :term:`OGC API - Processes`. + :param provider_id: Identifier to employ for unregistering the :term:`Provider`. :param url: Instance URL if not already provided during client creation. :param auth: @@ -629,8 +649,13 @@ def deploy(self, If the reference is resolved to be a :term:`Workflow`, all its underlying :term:`Process` steps must be available under the same URL that this client was initialized with. + .. note:: + This is only supported by :term:`OGC API - Processes` instances that support + the `Deploy, Replace, Undeploy` (DRU) extension. + .. seealso:: - :ref:`proc_op_deploy` + - :ref:`proc_op_deploy` + - |ogc-api-proc-part2|_ :param process_id: Desired process identifier. @@ -856,6 +881,48 @@ def _get_process_url(self, url, process_id, provider_id=None): path = f"{base}/processes/{process_id}" return path + def package(self, + process_id, # type: str + provider_id=None, # type: Optional[str] + url=None, # type: Optional[str] + auth=None, # type: Optional[AuthHandler] + headers=None, # type: Optional[AnyHeadersContainer] + with_links=True, # type: bool + with_headers=False, # type: bool + request_timeout=None, # type: Optional[int] + request_retries=None, # type: Optional[int] + output_format=None, # type: Optional[AnyOutputFormat] + ): # type: (...) -> OperationResult + """ + Retrieve the :term:`Application Package` definition of the specified :term:`Process`. + + .. note:: + This operation is specific to `Weaver`. It is not supported by standard :term:`OGC API - Processes`. + + :param process_id: Identifier of the local or remote process to describe. + :param provider_id: Identifier of the provider from which to locate a remote process to describe. + :param url: Instance URL if not already provided during client creation. + :param auth: + Instance authentication handler if not already created during client creation. + Should perform required adjustments to request to allow access control of protected contents. + :param headers: + Additional headers to employ when sending request. + Note that this can break functionalities if expected headers are overridden. Use with care. + :param with_links: Indicate if ``links`` section should be preserved in returned result body. + :param with_headers: Indicate if response headers should be returned in result output. + :param request_timeout: Maximum timout duration (seconds) to wait for a response when performing HTTP requests. + :param request_retries: Amount of attempt to retry HTTP requests in case of failure. + :param output_format: Select an alternate output representation of the result body contents. + :returns: Results of the operation. + """ + path = self._get_process_url(url, process_id, provider_id) + path = f"{path}/package" + resp = self._request("GET", path, + headers=self._headers, x_headers=headers, settings=self._settings, auth=auth, + request_timeout=request_timeout, request_retries=request_retries) + return self._parse_result(resp, message="Retrieving process Application Package.", + output_format=output_format, with_links=with_links, with_headers=with_headers) + @staticmethod def _parse_inputs(inputs): # type: (Optional[Union[str, JSON]]) -> Union[OperationResult, ExecutionInputsMap] @@ -2365,6 +2432,17 @@ def make_parser(): help="Representation schema of the returned process description (default: %(default)s, case-insensitive)." ) + op_package = WeaverArgumentParser( + "package", + description="Obtain the Application Package definition of an existing process.", + formatter_class=ParagraphFormatter, + ) + set_parser_sections(op_package) + add_url_param(op_package) + add_shared_options(op_package) + add_process_param(op_package) + add_provider_param(op_package, required=False) + op_execute = WeaverArgumentParser( "execute", description="Submit a job execution for an existing process.", @@ -2606,6 +2684,7 @@ def make_parser(): op_unregister, op_capabilities, op_describe, + op_package, op_execute, op_jobs, op_monitor, diff --git a/weaver/wps_restapi/providers/__init__.py b/weaver/wps_restapi/providers/__init__.py index eb2e1bd58..d10277cc4 100644 --- a/weaver/wps_restapi/providers/__init__.py +++ b/weaver/wps_restapi/providers/__init__.py @@ -19,6 +19,7 @@ def includeme(config): config.add_route(**sd.service_api_route_info(sd.provider_service, settings)) config.add_route(**sd.service_api_route_info(sd.provider_processes_service, settings)) config.add_route(**sd.service_api_route_info(sd.provider_process_service, settings)) + config.add_route(**sd.service_api_route_info(sd.provider_process_package_service, settings)) config.add_route(**sd.service_api_route_info(sd.provider_execution_service, settings)) config.add_view(p.get_providers, route_name=sd.providers_service.name, request_method="GET", renderer=OutputFormat.JSON) @@ -32,6 +33,8 @@ def includeme(config): request_method="GET", renderer=OutputFormat.JSON) config.add_view(p.get_provider_process, route_name=sd.provider_process_service.name, request_method="GET", renderer=OutputFormat.JSON) + config.add_view(p.get_provider_process_package, route_name=sd.provider_process_package_service.name, + request_method="GET", renderer=OutputFormat.JSON) config.add_view(p.submit_provider_job, route_name=sd.provider_jobs_service.name, request_method="POST", renderer=OutputFormat.JSON) config.add_view(p.submit_provider_job, route_name=sd.provider_execution_service.name, diff --git a/weaver/wps_restapi/providers/providers.py b/weaver/wps_restapi/providers/providers.py index ccc9637d9..8e2427d52 100644 --- a/weaver/wps_restapi/providers/providers.py +++ b/weaver/wps_restapi/providers/providers.py @@ -149,7 +149,7 @@ def get_provider(request): return HTTPOk(json=data) -@sd.provider_processes_service.get(tags=[sd.TAG_PROVIDERS, sd.TAG_PROCESSES, sd.TAG_PROVIDERS, sd.TAG_GETCAPABILITIES], +@sd.provider_processes_service.get(tags=[sd.TAG_PROVIDERS, sd.TAG_PROCESSES, sd.TAG_GETCAPABILITIES], renderer=OutputFormat.JSON, schema=sd.ProviderProcessesEndpoint(), response_schemas=sd.get_provider_processes_responses) @log_unhandled_exceptions(logger=LOGGER, message=sd.InternalServerErrorResponseSchema.description) @@ -190,7 +190,7 @@ def describe_provider_process(request): return Process.convert(process, service, get_settings(request)) -@sd.provider_process_service.get(tags=[sd.TAG_PROVIDERS, sd.TAG_PROCESSES, sd.TAG_PROVIDERS, sd.TAG_DESCRIBEPROCESS], +@sd.provider_process_service.get(tags=[sd.TAG_PROVIDERS, sd.TAG_PROCESSES, sd.TAG_DESCRIBEPROCESS], renderer=OutputFormat.JSON, schema=sd.ProviderProcessEndpoint(), response_schemas=sd.get_provider_process_responses) @log_unhandled_exceptions(logger=LOGGER, message=sd.InternalServerErrorResponseSchema.description) @@ -199,7 +199,7 @@ def describe_provider_process(request): def get_provider_process(request): # type: (PyramidRequest) -> AnyViewResponse """ - Retrieve a process description (DescribeProcess). + Retrieve a remote provider's process description (DescribeProcess). """ process = describe_provider_process(request) schema = request.params.get("schema") @@ -207,10 +207,24 @@ def get_provider_process(request): return HTTPOk(json=offering) -@sd.provider_execution_service.post(tags=[sd.TAG_PROVIDERS, sd.TAG_PROVIDERS, sd.TAG_EXECUTE, sd.TAG_JOBS], +@sd.provider_process_package_service.get(tags=[sd.TAG_PROVIDERS, sd.TAG_PROCESSES, sd.TAG_DESCRIBEPROCESS], + renderer=OutputFormat.JSON, schema=sd.ProviderProcessPackageEndpoint(), + response_schemas=sd.get_provider_process_package_responses) +@log_unhandled_exceptions(logger=LOGGER, message=sd.InternalServerErrorResponseSchema.description) +@check_provider_requirements +def get_provider_process_package(request): + # type: (PyramidRequest) -> AnyViewResponse + """ + Retrieve a remote provider's process Application Package definition. + """ + process = describe_provider_process(request) + return HTTPOk(json=process.package or {}) + + +@sd.provider_execution_service.post(tags=[sd.TAG_PROVIDERS, sd.TAG_PROCESSES, sd.TAG_EXECUTE, sd.TAG_JOBS], renderer=OutputFormat.JSON, schema=sd.PostProviderProcessJobRequest(), response_schemas=sd.post_provider_process_job_responses) -@sd.provider_jobs_service.post(tags=[sd.TAG_PROVIDERS, sd.TAG_PROVIDERS, sd.TAG_EXECUTE, sd.TAG_JOBS], +@sd.provider_jobs_service.post(tags=[sd.TAG_PROVIDERS, sd.TAG_PROCESSES, sd.TAG_EXECUTE, sd.TAG_JOBS], renderer=OutputFormat.JSON, schema=sd.PostProviderProcessJobRequest(), response_schemas=sd.post_provider_process_job_responses) @log_unhandled_exceptions(logger=LOGGER, message=sd.InternalServerErrorResponseSchema.description) diff --git a/weaver/wps_restapi/swagger_definitions.py b/weaver/wps_restapi/swagger_definitions.py index c55d9730f..bb1706e5d 100644 --- a/weaver/wps_restapi/swagger_definitions.py +++ b/weaver/wps_restapi/swagger_definitions.py @@ -311,6 +311,7 @@ provider_service = Service(name="provider", path=f"{providers_service.path}/{{provider_id}}") provider_processes_service = Service(name="provider_processes", path=provider_service.path + processes_service.path) provider_process_service = Service(name="provider_process", path=provider_service.path + process_service.path) +provider_process_package_service = Service(name="provider_process_pkg", path=f"{provider_process_service.path}/package") provider_jobs_service = Service(name="provider_jobs", path=provider_service.path + process_jobs_service.path) provider_job_service = Service(name="provider_job", path=provider_service.path + process_job_service.path) provider_results_service = Service(name="provider_results", path=provider_service.path + process_results_service.path) @@ -2796,6 +2797,10 @@ class ProcessPackageEndpoint(LocalProcessPath): querystring = LocalProcessQuery() +class ProviderProcessPackageEndpoint(ProviderProcessPath, ProcessPackageEndpoint): + pass + + class ProcessPayloadEndpoint(LocalProcessPath): header = RequestHeaders() querystring = LocalProcessQuery() @@ -6633,6 +6638,10 @@ class GoneVaultFileDownloadResponse(ExtendedMappingSchema): "405": MethodNotAllowedErrorResponseSchema(), "500": InternalServerErrorResponseSchema(), } +get_provider_process_package_responses = copy(get_process_package_responses) +get_provider_process_package_responses.update({ + "403": ForbiddenProviderAccessResponseSchema(), +}) post_provider_responses = { "201": CreatedPostProvider(description="success"), "400": ExtendedMappingSchema(description=OWSMissingParameterValue.description), From 366823a12c3a5220ec24538836c2d8286b75e64a Mon Sep 17 00:00:00 2001 From: Francis Charette Migneault Date: Fri, 15 Sep 2023 18:32:21 -0400 Subject: [PATCH 2/5] update changelog --- CHANGES.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.rst b/CHANGES.rst index cc11fa570..c4828ab9c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -15,6 +15,7 @@ Changes: - Add ``GET /providers/{provider_id}/processes/{process_id}/package`` endpoint that allows retrieval of the `CWL` `Application Package` definition generated for the specific `Provider`'s `Process` definition. - Add `CLI` ``package`` operation to request the remote `Provider` or local `Process` `CWL` `Application Package`. +- Add `CLI` output reporting of performed HTTP requests details when using the ``--debug/-d`` option. Fixes: ------ From 9f8acabd771e69be874ac4db8f919b1587295bc1 Mon Sep 17 00:00:00 2001 From: Francis Charette Migneault Date: Fri, 15 Sep 2023 21:53:37 -0400 Subject: [PATCH 3/5] CLI fixes and default handling of visiblity flag --- CHANGES.rst | 11 +++ tests/functional/test_cli.py | 102 ++++++++++++++++++++++ tests/functional/utils.py | 8 +- weaver/cli.py | 6 +- weaver/datatype.py | 2 +- weaver/processes/utils.py | 4 +- weaver/wps_restapi/swagger_definitions.py | 8 -- 7 files changed, 128 insertions(+), 13 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index c4828ab9c..df920a2b4 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -16,6 +16,13 @@ Changes: `Application Package` definition generated for the specific `Provider`'s `Process` definition. - Add `CLI` ``package`` operation to request the remote `Provider` or local `Process` `CWL` `Application Package`. - Add `CLI` output reporting of performed HTTP requests details when using the ``--debug/-d`` option. +- Modify default behavior of ``visibility`` field (under ``processDescription`` or ``processDescription.process``) + to employ the expected functionality by native `OGC API - Processes` clients that do not support this option + (i.e.: ``public`` by default), and to align resolution strategy with deployments by direct `CWL` payload which do not + include this feature either. A `Process` deployment that desires to employ this feature (``visibility: private``) will + have to provide the value explicitly, or update the deployed `Process` definition afterwards with the relevant + ``PUT`` request. Since ``public`` will now be used by default, the `CLI` will not automatically inject the value + in the payload anymore when omitted. Fixes: ------ @@ -27,6 +34,10 @@ Fixes: - Fix ``get_cwl_io_type`` function that would modify the I/O definition passed as argument, which could lead to failing `CWL` ``class`` reference resolutions later on due to different ``type`` with ``org.w3id.cwl.cwl`` prefix simplified before ``cwltool`` had the chance to resolve them. +- Fix ``links`` listing duplicated in response from `Process` deployment. + Links will only be listed within the returned ``processSummary`` to respect the `OGC API - Processes` schema. +- Fix `CLI` not removing embedded ``links`` in ``processSummary`` from ``deploy`` operation response + when ``-nL``/``--no-links`` option is specified. .. _changes_4.31.0: diff --git a/tests/functional/test_cli.py b/tests/functional/test_cli.py index 307e08530..cb346798b 100644 --- a/tests/functional/test_cli.py +++ b/tests/functional/test_cli.py @@ -102,6 +102,8 @@ def tearDownClass(cls): class TestWeaverClient(TestWeaverClientBase): + test_tmp_dir = None # type: str + @classmethod def setUpClass(cls): super(TestWeaverClient, cls).setUpClass() @@ -342,6 +344,40 @@ def test_deploy_with_undeploy(self): assert result.success assert "undefined" not in result.message + def test_deploy_private_process_description(self): + test_id = f"{self.test_process_prefix}private-process-description" + payload = self.retrieve_payload("Echo", "deploy", local=True) + package = self.retrieve_payload("Echo", "package", local=True) + payload.pop("executionUnit", None) + process = payload["processDescription"].pop("process") + payload["processDescription"].update(process) + payload["processDescription"]["visibility"] = Visibility.PRIVATE + + result = mocked_sub_requests(self.app, self.client.deploy, test_id, payload, package) + assert result.success + assert "processSummary" in result.body + assert result.body["processSummary"]["id"] == test_id + + result = mocked_sub_requests(self.app, self.client.describe, test_id) + assert not result.success + assert result.code == 403 + + def test_deploy_private_process_nested(self): + test_id = f"{self.test_process_prefix}private-process-nested" + payload = self.retrieve_payload("Echo", "deploy", local=True) + package = self.retrieve_payload("Echo", "package", local=True) + payload.pop("executionUnit", None) + payload["processDescription"]["process"]["visibility"] = Visibility.PRIVATE + + result = mocked_sub_requests(self.app, self.client.deploy, test_id, payload, package) + assert result.success + assert "processSummary" in result.body + assert result.body["processSummary"]["id"] == test_id + + result = mocked_sub_requests(self.app, self.client.describe, test_id) + assert not result.success + assert result.code == 403 + def test_undeploy(self): # deploy a new process to leave the test one available other_payload = copy.deepcopy(self.test_payload["Echo"]) @@ -771,6 +807,7 @@ def test_deploy_no_process_id_option(self): "-u", self.url, "--body", payload, # no --process/--id, but available through --body "--cwl", package, + "-D", # avoid conflict just in case ], trim=False, entrypoint=weaver_cli, @@ -779,6 +816,28 @@ def test_deploy_no_process_id_option(self): assert any("\"id\": \"Echo\"" in line for line in lines) assert any("\"deploymentDone\": true" in line for line in lines) + def test_deploy_no_links(self): + payload = self.retrieve_payload("Echo", "deploy", local=True, ref_found=True) + package = self.retrieve_payload("Echo", "package", local=True, ref_found=True) + lines = mocked_sub_requests( + self.app, run_command, + [ + # "weaver", + "deploy", + "-u", self.url, + "--body", payload, + "--cwl", package, + "-nL", + "-D", + ], + trim=False, + entrypoint=weaver_cli, + only_local=True, + ) + # ignore indents of fields from formatted JSON content + assert any("\"id\": \"Echo\"" in line for line in lines) + assert all("\"links\":" not in line for line in lines) + def test_deploy_docker_auth_help(self): """ Validate some special handling to generate special combinations of help argument details. @@ -1255,6 +1314,49 @@ def test_describe_no_links(self): assert any("\"outputs\": {" in line for line in lines) assert all("\"links\":" not in line for line in lines) + def test_package_process(self): + payload = self.retrieve_payload("Echo", "deploy", local=True, ref_found=True) + package = self.retrieve_payload("Echo", "package", local=True) + lines = mocked_sub_requests( + self.app, run_command, + [ + # weaver + "deploy", + "-u", self.url, + "--body", payload, + "--cwl", package, + "--id", "test-echo-get-package" + ], + trim=False, + entrypoint=weaver_cli, + only_local=True, + ) + assert any("\"id\": \"test-echo-get-package\"" in line for line in lines) + + lines = mocked_sub_requests( + self.app, run_command, + [ + # weaver + "package", + "-u", self.url, + "-p", "test-echo-get-package" + ], + trim=False, + entrypoint=weaver_cli, + only_local=True, + ) + assert any("\"cwlVersion\"" in line for line in lines) + cwl = json.loads("".join(lines)) + + # package not 100% the same, but equivalent definitions + # check that what is returned is at least relatively equal + cwl.pop("$id", None) + cwl.pop("$schema", None) + pkg = package.copy() + pkg["inputs"] = [dict(id=key, **val) for key, val in package["inputs"].items()] + pkg["outputs"] = [dict(id=key, **val) for key, val in package["outputs"].items()] + assert cwl == pkg + def test_execute_inputs_capture(self): """ Verify that specified inputs are captured for a limited number of 1 item per ``-I`` option. diff --git a/tests/functional/utils.py b/tests/functional/utils.py index b11c00e40..e77657401 100644 --- a/tests/functional/utils.py +++ b/tests/functional/utils.py @@ -38,6 +38,9 @@ from typing import Any, Dict, Iterable, Optional, Tuple, Union from typing_extensions import Literal + from pyramid.config import Configurator + from webtest import TestApp + from weaver.typedefs import ( AnyRequestMethod, AnyResponseType, @@ -305,7 +308,10 @@ class WpsConfigBase(unittest.TestCase): json_headers = {"Accept": ContentType.APP_JSON, "Content-Type": ContentType.APP_JSON} monitor_timeout = 30 monitor_interval = 1 - settings = {} # type: SettingsType + settings = {} # type: SettingsType + config = None # type: Configurator + app = None # type: TestApp + url = None # type: str def __init__(self, *args, **kwargs): # won't run this as a test suite, only its derived classes diff --git a/weaver/cli.py b/weaver/cli.py index 19174a775..60d2d453f 100644 --- a/weaver/cli.py +++ b/weaver/cli.py @@ -435,6 +435,8 @@ def _parse_result(response, # type: Union[Response, OperationResult] for item in nested: if isinstance(item, dict): item.pop("links", None) + elif isinstance(nested, dict): + nested.pop("links", None) body.pop("links", None) msg = body.get("description", body.get("message", "undefined")) if code >= 400: @@ -484,7 +486,6 @@ def _parse_deploy_body(body, process_id): desc = data.get("processDescription", {}).get("process", {}) or data.get("processDescription", {}) desc["id"] = process_id data.setdefault("processDescription", desc) # already applied if description was found/updated at any level - desc["visibility"] = Visibility.PUBLIC except (ValueError, TypeError, ScannerError) as exc: # pragma: no cover return OperationResult(False, f"Failed resolution of body definition: [{exc!s}]", body) return OperationResult(True, "", data) @@ -711,7 +712,8 @@ def deploy(self, resp = self._request("POST", path, json=data, headers=req_headers, x_headers=headers, settings=self._settings, auth=auth, request_timeout=request_timeout, request_retries=request_retries) - return self._parse_result(resp, with_links=with_links, with_headers=with_headers, output_format=output_format) + return self._parse_result(resp, with_links=with_links, nested_links="processSummary", + with_headers=with_headers, output_format=output_format) def undeploy(self, process_id, # type: str diff --git a/weaver/datatype.py b/weaver/datatype.py index cbeea073a..ffc36d0ed 100644 --- a/weaver/datatype.py +++ b/weaver/datatype.py @@ -2247,7 +2247,7 @@ def estimator(self, estimator): @property def visibility(self): # type: () -> Visibility - return Visibility.get(self.get("visibility"), Visibility.PRIVATE) + return Visibility.get(self.get("visibility"), Visibility.PUBLIC) @visibility.setter def visibility(self, visibility): diff --git a/weaver/processes/utils.py b/weaver/processes/utils.py index 7fd12ca0d..a5737bf78 100644 --- a/weaver/processes/utils.py +++ b/weaver/processes/utils.py @@ -450,6 +450,7 @@ def deploy_process_from_payload(payload, container, overwrite=False): # pylint: process_info["jobControlOptions"] = process_desc.get("jobControlOptions", []) process_info["outputTransmission"] = process_desc.get("outputTransmission", []) process_info["processDescriptionURL"] = description_url + # insert the "resolved" context using details retrieved from "executionUnit"/"href" or directly with "owsContext" if "owsContext" not in process_info and reference: process_info["owsContext"] = {"offering": {"content": {"href": str(reference)}}} @@ -476,11 +477,12 @@ def deploy_process_from_payload(payload, container, overwrite=False): # pylint: raise HTTPBadRequest(detail=str(exc)) except HTTPException: raise + links = process.links(container) + process_summary["links"] = links data = { "description": sd.OkPostProcessesResponse.description, "processSummary": process_summary, "deploymentDone": True, - "links": process.links(container), } if deployment_profile_name: data["deploymentProfileName"] = deployment_profile_name diff --git a/weaver/wps_restapi/swagger_definitions.py b/weaver/wps_restapi/swagger_definitions.py index bb1706e5d..fb4b4adca 100644 --- a/weaver/wps_restapi/swagger_definitions.py +++ b/weaver/wps_restapi/swagger_definitions.py @@ -4844,14 +4844,6 @@ class Unit(ExtendedMappingSchema): unit = CWL(description=f"Execution unit definition as CWL package specification. {CWL_DOC_MESSAGE}") -class UndeploymentResult(ExtendedMappingSchema): - id = AnyIdentifier() - - -class DeploymentResult(ExtendedMappingSchema): - processSummary = ProcessSummary() - - class ProviderSummaryList(ExtendedSequenceSchema): provider_service = ProviderSummarySchema() From 146f98df903b6c5986e99f0f3a6e7c34c13fa68a Mon Sep 17 00:00:00 2001 From: Francis Charette Migneault Date: Fri, 15 Sep 2023 21:56:09 -0400 Subject: [PATCH 4/5] fix linting --- tests/functional/test_cli.py | 4 ++-- weaver/cli.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/functional/test_cli.py b/tests/functional/test_cli.py index cb346798b..4b576e47c 100644 --- a/tests/functional/test_cli.py +++ b/tests/functional/test_cli.py @@ -1353,8 +1353,8 @@ def test_package_process(self): cwl.pop("$id", None) cwl.pop("$schema", None) pkg = package.copy() - pkg["inputs"] = [dict(id=key, **val) for key, val in package["inputs"].items()] - pkg["outputs"] = [dict(id=key, **val) for key, val in package["outputs"].items()] + pkg["inputs"] = [dict(id=key, **val) for key, val in package["inputs"].items()] # noqa + pkg["outputs"] = [dict(id=key, **val) for key, val in package["outputs"].items()] # noqa assert cwl == pkg def test_execute_inputs_capture(self): diff --git a/weaver/cli.py b/weaver/cli.py index 60d2d453f..62520c602 100644 --- a/weaver/cli.py +++ b/weaver/cli.py @@ -53,7 +53,6 @@ request_extra, setup_loggers ) -from weaver.visibility import Visibility from weaver.wps_restapi import swagger_definitions as sd if TYPE_CHECKING: From d1f961a432e30e5a44f18d7bf867e3f378ea3465 Mon Sep 17 00:00:00 2001 From: Francis Charette Migneault Date: Mon, 18 Sep 2023 09:50:12 -0400 Subject: [PATCH 5/5] ignore lint false-positive in test --- tests/functional/test_cli.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/functional/test_cli.py b/tests/functional/test_cli.py index 4b576e47c..2a3d0801d 100644 --- a/tests/functional/test_cli.py +++ b/tests/functional/test_cli.py @@ -1353,8 +1353,8 @@ def test_package_process(self): cwl.pop("$id", None) cwl.pop("$schema", None) pkg = package.copy() - pkg["inputs"] = [dict(id=key, **val) for key, val in package["inputs"].items()] # noqa - pkg["outputs"] = [dict(id=key, **val) for key, val in package["outputs"].items()] # noqa + pkg["inputs"] = [{"id": key, **val} for key, val in package["inputs"].items()] # pylint: disable=E1136 + pkg["outputs"] = [{"id": key, **val} for key, val in package["outputs"].items()] # pylint: disable=E1136 assert cwl == pkg def test_execute_inputs_capture(self):