Esempio n. 1
0
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
Esempio n. 2
0
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)"
Esempio n. 3
0
    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
Esempio n. 4
0
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 == ""
Esempio n. 5
0
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 == ""
Esempio n. 6
0
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
Esempio n. 7
0
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