Ejemplo n.º 1
0
def test_get_exception_from_xml_status(xml_file, ows_exception):
    # pylint: disable=C0123  # use type instead of isinstance, since we actually want to exclude classes inheritance
    xml_str = load_example(xml_file, text=True)
    xml = xml_util.fromstring(xml_str)
    exc = get_exception_from_xml_status(xml)
    assert isinstance(exc, OWSException) and type(
        exc) is not OWSException, "Should be the exact derived type"
    assert exc.code == ows_exception.code
Ejemplo n.º 2
0
def get_exception_from_xml_status(xml):
    # type: (Union[xml_util.XML, str]) -> Optional[owsexceptions.OWSException]
    """
    Retrieves the :term:`OWS` exception that corresponds to the :term:`XML` status.

    Expects the following :term:`XML` status response structure (``ows:Exception`` block can be at any level):

    .. code-block:: xml
        <ows:Exception exceptionCode="NoApplicableCode" locator="None">
          <ows:ExceptionText>Error message about the cause of the exception.</ows:ExceptionText>
        </ows:Exception>

    :param xml: XML tree object with exception details.
    :return:
        Matched :class:`owsexceptions.OWSException`.
        If no matching exception code is found within available exception classes, defaults to generic ``OWSException``.
        If any parsing error occurs, returns nothing.
    """

    try:
        if isinstance(xml, (str, bytes)):
            xml = xml_util.fromstring(bytes2str(xml))
        if not isinstance(xml, xml_util.XML):
            return None
        # Exception blocks can be with or without 'ows' prefix depending on which default namespace was defined
        ows_exc_xml = xml.find(
            "Exception", namespaces=xml.nsmap)  # type: Optional[xml_util.XML]
        if ows_exc_xml is None:
            ows_exc_xml = xml.xpath(
                "//ows:Exception",
                namespaces=xml.nsmap)[0]  # type: Optional[xml_util.XML]
        ows_exc_txt = ows_exc_xml.find(
            "ExceptionText",
            namespaces=xml.nsmap)  # type: Optional[xml_util.XML]
        if ows_exc_txt is None:
            ows_exc_txt = ows_exc_xml.xpath("//ows:ExceptionText",
                                            namespaces=xml.nsmap)[0]
        ows_exc_msg = ows_exc_txt.text
        ows_exc_loc = ows_exc_xml.attrib.get(
            "locator") or ows_exc_xml.attrib.get(
                "locater")  # some WPS have typo
        ows_exc_code = ows_exc_xml.attrib["exceptionCode"]
        for ows_exc_name in dir(owsexceptions):
            ows_exc_cls = getattr(owsexceptions, ows_exc_name)
            if (inspect.isclass(ows_exc_cls)
                    and issubclass(ows_exc_cls, owsexceptions.OWSException)
                    and ows_exc_cls is not owsexceptions.OWSException
                    and ows_exc_code == ows_exc_cls.code):
                return ows_exc_cls(ows_exc_msg,
                                   code=ows_exc_code,
                                   locator=ows_exc_loc)
        return owsexceptions.OWSException(ows_exc_msg,
                                          code=ows_exc_code,
                                          locator=ows_exc_loc)
    except Exception as exc:
        LOGGER.error("Failed mapping of OWS Exception from error codes.",
                     exc_info=exc)
    return None
Ejemplo n.º 3
0
    def get_template_url(self):
        resp = request_extra("get",
                             self.osdd_url,
                             params=self.params,
                             settings=self.settings)
        resp.raise_for_status()

        data = xml_util.fromstring(resp.content)
        xpath = "//*[local-name() = 'Url'][@rel='results']"
        url = data.xpath(xpath)[0]  # type: xml_util.XML
        return url.attrib["template"]
Ejemplo n.º 4
0
def test_xml_strip_ns():
    wps_xml = """
<wps100:Execute
xmlns:wps100="http://www.opengis.net/wps/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
service="WPS"
version="1.0.0"
xsi:schemaLocation="http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsExecute_request.xsd"/>"""

    doc = xml_util.fromstring(wps_xml)
    assert doc.tag == "{http://www.opengis.net/wps/1.0.0}Execute"
    xml_strip_ns(doc)
    assert doc.tag == "Execute"
Ejemplo n.º 5
0
    def _fetch_datatsets_from_alternates_links(self, alternate_links):
        # Try loading from atom alternate link
        for link in alternate_links:
            if link["type"] == "application/atom+xml":
                resp = request_extra("get",
                                     link["href"],
                                     settings=self.settings)
                resp.raise_for_status()

                data = xml_util.fromstring(resp.content)
                xpath = "//*[local-name() = 'entry']/*[local-name() = 'link']"
                links = data.xpath(xpath)  # type: List[xml_util.XML]
                return [link.attrib for link in links]
        return []
Ejemplo n.º 6
0
 def test_getcaps_filtered_processes_by_visibility(self):
     resp = self.app.get(
         self.make_url("service=wps&request=getcapabilities"))
     assert resp.status_code == 200
     assert resp.content_type in CONTENT_TYPE_ANY_XML
     resp.mustcontain("<wps:ProcessOfferings>")
     root = xml_util.fromstring(str2bytes(
         resp.text))  # test response has no 'content'
     process_offerings = list(
         filter(lambda e: "ProcessOfferings" in e.tag,
                root.iter(xml_util.Element)))
     assert len(process_offerings) == 1
     processes = [p for p in process_offerings[0]]
     ids = [
         pi.text for pi in [
             list(filter(lambda e: e.tag.endswith("Identifier"), p))[0]
             for p in processes
         ]
     ]
     assert self.process_private.identifier not in ids
     assert self.process_public.identifier in ids
Ejemplo n.º 7
0
def check_wps_status(
        location=None,  # type: Optional[str]
        response=None,  # type: Optional[xml_util.XML]
        sleep_secs=2,  # type: int
        verify=True,  # type: bool
        settings=None,  # type: Optional[AnySettingsContainer]
):  # type: (...) -> WPSExecution
    """
    Run :func:`owslib.wps.WPSExecution.checkStatus` with additional exception handling.

    :param location: job URL or file path where to look for job status.
    :param response: WPS response document of job status.
    :param sleep_secs: number of seconds to sleep before returning control to the caller.
    :param verify: flag to enable SSL verification.
    :param settings: application settings to retrieve any additional request parameters as applicable.
    :returns: OWSLib.wps.WPSExecution object.
    """
    def _retry_file():
        # type: () -> str
        LOGGER.warning(
            "Failed retrieving WPS status-location, attempting with local file."
        )
        out_path = get_wps_local_status_location(location, settings)
        if not out_path:
            raise HTTPNotFound(
                f"Could not find file resource from [{location}].")
        LOGGER.info("Resolved WPS status-location using local file reference.")
        with open(out_path, mode="r", encoding="utf-8") as f:
            return f.read()

    execution = WPSExecution()
    if response:
        LOGGER.debug("Retrieving WPS status from XML response document...")
        xml_data = response
    elif location:
        xml_resp = HTTPNotFound()
        xml_data = None
        try:
            LOGGER.debug(
                "Attempt to retrieve WPS status-location from URL [%s]...",
                location)
            xml_resp = request_extra("get",
                                     location,
                                     verify=verify,
                                     settings=settings)
            xml_data = xml_resp.content
        except Exception as ex:
            LOGGER.debug(
                "Got exception during get status: [%r]. Will retry with local reference.",
                ex)
        if xml_resp.status_code != HTTPOk.code:
            LOGGER.debug(
                "WPS XML status not found: [%r]. Retrying with local reference.",
                xml_data)
            xml_data = _retry_file()
    else:
        raise Exception(
            "Missing status-location URL/file reference or response with XML object."
        )
    if isinstance(xml_data, str):
        xml_data = xml_data.encode("utf8", errors="ignore")
    execution.checkStatus(response=xml_data, sleepSecs=sleep_secs)
    if execution.response is None:
        raise Exception("Missing response, cannot check status.")
    if not isinstance(execution.response, xml_util.XML):
        execution.response = xml_util.fromstring(execution.response)
    return execution
Ejemplo n.º 8
0
def test_get_exception_from_xml_status_unknown_other_exception():
    xml = xml_util.fromstring("<FakeException>Not valid</FakeException>")
    exc = get_exception_from_xml_status(xml)
    assert exc is None
Ejemplo n.º 9
0
    def wps_execute(self, version, accept):
        wps_url = get_wps_url(self.settings)
        if version == "1.0.0":
            test_content = "Test file in Docker - WPS KVP"
            wps_method = "GET"
        elif version == "2.0.0":
            test_content = "Test file in Docker - WPS XML"
            wps_method = "POST"
        else:
            raise ValueError("Invalid WPS version: {}".format(version))
        test_content += " {} request - Accept {}".format(wps_method, accept.split("/")[-1].upper())

        with contextlib.ExitStack() as stack_exec:
            # setup
            dir_name = tempfile.gettempdir()
            tmp_file = stack_exec.enter_context(tempfile.NamedTemporaryFile(dir=dir_name, mode="w", suffix=".txt"))
            tmp_file.write(test_content)
            tmp_file.seek(0)
            for mock_exec in mocked_execute_process():
                stack_exec.enter_context(mock_exec)

            # execute
            if version == "1.0.0":
                wps_inputs = ["file={}@mimeType={}".format(tmp_file.name, CONTENT_TYPE_TEXT_PLAIN)]
                wps_params = {
                    "service": "WPS",
                    "request": "Execute",
                    "version": version,
                    "identifier": self.process_id,
                    "DataInputs": wps_inputs,
                }
                wps_headers = {"Accept": accept}
                wps_data = None
            else:
                wps_inputs = [("file", ComplexDataInput(tmp_file.name, mimeType=CONTENT_TYPE_TEXT_PLAIN))]
                wps_outputs = [(self.out_key, True)]  # as reference
                wps_exec = WPSExecution(version=version, url=wps_url)
                wps_req = wps_exec.buildRequest(self.process_id, wps_inputs, wps_outputs)
                wps_data = xml_util.tostring(wps_req)
                wps_headers = {"Accept": accept, "Content-Type": CONTENT_TYPE_APP_XML}
                wps_params = None
            resp = mocked_sub_requests(self.app, wps_method, wps_url,
                                       params=wps_params, data=wps_data, headers=wps_headers, only_local=True)
            assert resp.status_code in [200, 201], (
                "Failed with: [{}]\nTest: [{}]\nReason:\n{}".format(resp.status_code, test_content, resp.text)
            )

            # parse response status
            if accept == CONTENT_TYPE_APP_XML:
                assert resp.content_type in CONTENT_TYPE_ANY_XML, test_content
                xml_body = xml_util.fromstring(str2bytes(resp.text))
                status_url = xml_body.get("statusLocation")
                job_id = status_url.split("/")[-1].split(".")[0]
            elif accept == CONTENT_TYPE_APP_JSON:
                assert resp.content_type == CONTENT_TYPE_APP_JSON, test_content
                status_url = resp.json["location"]
                job_id = resp.json["jobID"]
            assert status_url
            assert job_id

            if accept == CONTENT_TYPE_APP_XML:
                wps_out_url = self.settings["weaver.wps_output_url"]
                weaver_url = self.settings["weaver.url"]
                assert status_url == f"{wps_out_url}/{job_id}.xml", "Status URL should be XML file for WPS-1 request"
                # remap to employ JSON monitor method (could be done with XML parsing otherwise)
                status_url = f"{weaver_url}/jobs/{job_id}"

            # job monitoring
            results = self.monitor_job(status_url)
            outputs = self.get_outputs(status_url)

            # validate XML status is updated accordingly
            wps_xml_status = os.path.join(self.settings["weaver.wps_output_dir"], job_id + ".xml")
            assert os.path.isfile(wps_xml_status)
            with open(wps_xml_status, "r") as status_file:
                assert "ProcessSucceeded" in status_file.read()

        self.validate_outputs(job_id, results, outputs, test_content)