def test_get_format(): assert f.get_format(f.ContentType.APP_JSON) == Format( f.ContentType.APP_JSON) # basic assert f.get_format(f.ContentType.APP_JSON + "; charset=UTF-8") == Format( f.ContentType.APP_JSON) assert f.get_format(f.ContentType.APP_GEOJSON) == Format( f.ContentType.APP_GEOJSON) # pywps vendor MIME-type assert f.get_format(f.ContentType.APP_NETCDF ).encoding == "base64" # extra encoding data available
def test_get_cwl_file_format_synonym(): """ Test handling of special non-official MIME-type that have a synonym redirection to an official one. """ res = f.get_cwl_file_format(f.ContentType.APP_TAR_GZ, make_reference=False, must_exist=True, allow_synonym=False) assert res == ( None, None ), "Non-official MIME-type without allowed synonym should resolve as not-found" res = f.get_cwl_file_format(f.ContentType.APP_TAR_GZ, make_reference=False, must_exist=True, allow_synonym=True) assert isinstance(res, tuple) assert res != ( None, None), "Synonym type should have been mapped to its base reference" assert res[1].split( ":" )[1] == f.ContentType.APP_GZIP, "Synonym type should have been mapped to its base reference" assert f.get_extension( f.ContentType.APP_TAR_GZ ) == ".tar.gz", "Original extension resolution needed, not synonym" fmt = f.get_format(f.ContentType.APP_TAR_GZ) assert fmt.extension == ".tar.gz" assert fmt.mime_type == f.ContentType.APP_TAR_GZ # above tests validated that synonym is defined and works, so following must not use that synonym res = f.get_cwl_file_format(f.ContentType.APP_TAR_GZ, make_reference=True, must_exist=False, allow_synonym=True) assert res.endswith(f.ContentType.APP_TAR_GZ), \ "Literal MIME-type expected instead of its existing synonym since non-official is allowed (must_exist=False)"
def format_inputs(self, workflow_inputs): # type: (CWL_RuntimeInputList) -> OWS_InputDataValues """ Convert submitted :term:`CWL` workflow inputs into corresponding :mod:`OWSLib.wps` representation for execution. :param workflow_inputs: mapping of input IDs and values submitted to the workflow. :returns: converted OWS inputs ready for submission to remote WPS process. """ # prepare inputs complex_inputs = [] for process_input in self.wps_process.dataInputs: if WPS_COMPLEX_DATA in process_input.dataType: complex_inputs.append(process_input.identifier) wps_inputs = [] for input_item in workflow_inputs: input_key = get_any_id(input_item) input_val = get_any_value(input_item) # ignore optional inputs resolved as omitted if input_val is None: continue # in case of array inputs, must repeat (id,value) # in case of complex input (File), obtain location, otherwise get data value if not isinstance(input_val, list): input_val = [input_val] input_values = [] for val in input_val: mime_type = None encoding = None if isinstance(val, dict): fmt = val.get("format") # format as namespace:link val = val["location"] if fmt: fmt = get_format( fmt, default=DEFAULT_FORMAT) # format as content-type mime_type = fmt.mime_type or None encoding = fmt.encoding or None # avoid empty string # owslib only accepts strings, not numbers directly if isinstance(val, (int, float)): val = str(val) input_values.append((val, mime_type, encoding)) # need to use ComplexDataInput structure for complex input # TODO: BoundingBox not supported for input_value, mime_type, encoding in input_values: if input_key in complex_inputs: input_value = ComplexDataInput(input_value, mimeType=mime_type, encoding=encoding) wps_inputs.append((input_key, input_value)) return wps_inputs
def test_get_format_media_type_no_extension(): for ctype in [ f.ContentType.APP_OCTET_STREAM, f.ContentType.APP_FORM, f.ContentType.MULTI_PART_FORM, ]: fmt = f.get_format(ctype) assert fmt == Format(ctype, extension=None) assert fmt.extension == ""
def test_get_format_default_no_extension(): for val in ["", None]: for ctype in [ f.ContentType.APP_OCTET_STREAM, f.ContentType.APP_FORM, f.ContentType.MULTI_PART_FORM, ]: fmt = f.get_format(val, default=ctype) assert fmt == Format(ctype, extension=None) assert fmt.extension == ""
def get_results(job, container, value_key=None, ogc_api=False): # type: (Job, AnySettingsContainer, Optional[str], bool) -> Union[List[JSON], JSON] """ Obtains the job results with extended full WPS output URL as applicable and according to configuration settings. :param job: job from which to retrieve results. :param container: any container giving access to instance settings (to resolve reference output location). :param value_key: If not specified, the returned values will have the appropriate ``data``/``href`` key according to the content. Otherwise, all values will have the specified key. :param ogc_api: If ``True``, formats the results using the ``OGC API - Processes`` format. :returns: list of all outputs each with minimally an ID and value under the requested key. """ wps_url = get_wps_output_url(container) if not wps_url.endswith("/"): wps_url = wps_url + "/" outputs = {} if ogc_api else [] fmt_key = "mediaType" if ogc_api else "mimeType" for result in job.results: rtype = "data" if any(k in result for k in ["data", "value"]) else "href" value = get_any_value(result) out_id = get_any_id(result) out_key = rtype if rtype == "href": # fix paths relative to instance endpoint, but leave explicit links as is (eg: S3 bucket, remote HTTP, etc.) if value.startswith("/"): value = str(value).lstrip("/") if "://" not in value: value = wps_url + value elif ogc_api: out_key = "value" elif value_key: out_key = value_key output = {out_key: value} if rtype == "href": # required for the rest to be there, other fields optional if "mimeType" not in result: result["mimeType"] = get_format( value, default=CONTENT_TYPE_TEXT_PLAIN).mime_type output["format"] = {fmt_key: result["mimeType"]} for field in ["encoding", "schema"]: if field in result: output["format"][field] = result[field] elif rtype != "href": # literal data # FIXME: BoundingBox not implemented (https://github.com/crim-ca/weaver/issues/51) dtype = result.get( "dataType", any2wps_literal_datatype(value, is_value=True) or "string") if ogc_api: output["dataType"] = {"name": dtype} else: output["dataType"] = dtype if ogc_api: if out_id in outputs: output_list = outputs[out_id] if not isinstance(output_list, list): output_list = [output_list] output_list.append(output) outputs[out_id] = output_list else: outputs[out_id] = output else: # if ordered insert supported by python version, insert ID first output = dict([("id", out_id)] + list(output.items())) # noqa outputs.append(output) return outputs
def get_results( job, # type: Job container, # type: AnySettingsContainer value_key=None, # type: Optional[str] schema=JobInputsOutputsSchema.OLD, # type: JobInputsOutputsSchemaType link_references=False, # type: bool ): # type: (...) -> Tuple[ExecutionResults, HeadersTupleType] """ Obtains the job results with extended full WPS output URL as applicable and according to configuration settings. :param job: job from which to retrieve results. :param container: any container giving access to instance settings (to resolve reference output location). :param value_key: If not specified, the returned values will have the appropriate ``data``/``href`` key according to the content. Otherwise, all values will have the specified key. :param schema: Selects which schema to employ for representing the output results (listing or mapping). :param link_references: If enabled, an output that was requested by reference instead of value will be returned as ``Link`` reference. :returns: Tuple with: - List or mapping of all outputs each with minimally an ID and value under the requested key. - List of ``Link`` headers for reference outputs when requested. Empty otherwise. """ settings = get_settings(container) wps_url = get_wps_output_url(settings) if not wps_url.endswith("/"): wps_url = wps_url + "/" schema = JobInputsOutputsSchema.get(str(schema).lower(), default=JobInputsOutputsSchema.OLD) strict = schema.endswith("+strict") schema = schema.split("+")[0] ogc_api = schema == JobInputsOutputsSchema.OGC outputs = {} if ogc_api else [] fmt_key = "mediaType" if ogc_api else "mimeType" out_ref = convert_output_params_schema( job.outputs, JobInputsOutputsSchema.OGC) if link_references else {} references = {} for result in job.results: rtype = "data" if any(k in result for k in ["data", "value"]) else "href" value = get_any_value(result) out_key = rtype out_id = get_any_id(result) out_mode = out_ref.get(out_id, {}).get("transmissionMode") as_ref = link_references and out_mode == ExecuteTransmissionMode.REFERENCE if rtype == "href": # fix paths relative to instance endpoint, but leave explicit links as is (eg: S3 bucket, remote HTTP, etc.) if value.startswith("/"): value = str(value).lstrip("/") if "://" not in value: value = wps_url + value elif ogc_api: out_key = "value" elif value_key: out_key = value_key output = {out_key: value} if rtype == "href": # required for the rest to be there, other fields optional if "mimeType" not in result: result["mimeType"] = get_format( value, default=ContentType.TEXT_PLAIN).mime_type if ogc_api or not strict: output["type"] = result["mimeType"] if not ogc_api or not strict or as_ref: output["format"] = {fmt_key: result["mimeType"]} for field in ["encoding", "schema"]: if field in result: output["format"][field] = result[field] elif rtype != "href": # literal data # FIXME: BoundingBox not implemented (https://github.com/crim-ca/weaver/issues/51) dtype = result.get( "dataType", any2wps_literal_datatype(value, is_value=True) or "string") if ogc_api: output["dataType"] = {"name": dtype} else: output["dataType"] = dtype if ogc_api or as_ref: mapping = references if as_ref else outputs if out_id in mapping: output_list = mapping[out_id] if not isinstance(output_list, list): output_list = [output_list] output_list.append(output) mapping[out_id] = output_list else: mapping[out_id] = output else: # if ordered insert supported by python version, insert ID first output = dict([("id", out_id)] + list(output.items())) # noqa outputs.append(output) # needed to collect and aggregate outputs of same ID first in case of array # convert any requested link references using indices if needed headers = [] for out_id, output in references.items(): res_links = make_result_link(out_id, output, job.id, settings) headers.extend([("Link", link) for link in res_links]) return outputs, headers