Esempio n. 1
0
    def _method_factory(self, pid):
        """Create a custom function signature with docstring, instantiate it and
        pass it to a wrapper which will actually call the process.

        Parameters
        ----------
        pid: str
          Identifier of the WPS process.

        Returns
        -------
        func
          A Python function calling the remote process, complete with docstring and signature.
        """

        process = self._processes[pid]

        required_inputs_first = sorted(process.dataInputs, key=sort_inputs_key)

        input_names = []
        # defaults will be set to the function's __defaults__:
        # A tuple containing default argument values for those arguments that have defaults,
        # or None if no arguments have a default value.
        defaults = []
        for inpt in required_inputs_first:
            input_names.append(sanitize(inpt.identifier))
            if inpt.minOccurs == 0 or inpt.defaultValue is not None:
                default = inpt.defaultValue if inpt.dataType != "ComplexData" else None
                defaults.append(utils.from_owslib(default, inpt.dataType))
        defaults = tuple(defaults) if defaults else None

        body = dedent("""
            inputs = locals()
            inputs.pop('self')
            return self._execute('{pid}', **inputs)
        """).format(pid=pid)

        func_builder = FunctionBuilder(
            name=sanitize(pid),
            doc=utils.build_process_doc(process),
            args=["self"] + input_names,
            defaults=defaults,
            body=body,
            filename=__file__,
            module=self.__module__,
        )

        self._inputs[pid] = {}
        if hasattr(process, "dataInputs"):
            self._inputs[pid] = OrderedDict(
                (i.identifier, i) for i in process.dataInputs)

        self._outputs[pid] = {}
        if hasattr(process, "processOutputs"):
            self._outputs[pid] = OrderedDict(
                (o.identifier, o) for o in process.processOutputs)

        func = func_builder.get_func()

        return func
Esempio n. 2
0
 def _make_output(self, convert_objects=False):
     Output = namedtuple(
         sanitize(self.process.identifier) + 'Response',
         [sanitize(o.identifier) for o in self.processOutputs])
     Output.__repr__ = utils.pretty_repr
     return Output(*[
         self._process_output(o, convert_objects)
         for o in self.processOutputs
     ])
Esempio n. 3
0
    def _method_factory(self, pid):
        """Create a custom function signature with docstring, instantiate it and
        pass it to a wrapper which will actually call the process.

        Parameters
        ----------
        pid: str
          Identifier of the WPS process.

        Returns
        -------
        func
          A Python function calling the remote process, complete with docstring and signature.
        """

        process = self._processes[pid]

        input_defaults = OrderedDict()
        for inpt in process.dataInputs:
            iid = sanitize(inpt.identifier)
            default = getattr(inpt, "defaultValue", None) if inpt.dataType != 'ComplexData' else None
            input_defaults[iid] = utils.from_owslib(default, inpt.dataType)

        body = dedent("""
            inputs = locals()
            inputs.pop('self')
            return self._execute('{pid}', **inputs)
        """).format(pid=pid)

        func_builder = FunctionBuilder(
            name=sanitize(pid),
            doc=utils.build_process_doc(process),
            args=["self"] + list(input_defaults),
            defaults=tuple(input_defaults.values()),
            body=body,
            filename=__file__,
            module=self.__module__,
        )

        self._inputs[pid] = {}
        if hasattr(process, "dataInputs"):
            self._inputs[pid] = OrderedDict(
                (i.identifier, i) for i in process.dataInputs
            )

        self._outputs[pid] = {}
        if hasattr(process, "processOutputs"):
            self._outputs[pid] = OrderedDict(
                (o.identifier, o) for o in process.processOutputs
            )

        func = func_builder.get_func()

        return func
Esempio n. 4
0
def nb_form(wps, pid):
    """Return a Notebook form to enter input values and launch process."""
    if wps._notebook:
        return notebook.interact(func=getattr(wps, sanitize(pid)),
                                 inputs=list(wps._inputs[pid].items()))
    else:
        return None
Esempio n. 5
0
    def _execute(self, pid, **kwargs):
        """Execute the process."""
        wps_inputs = []
        for name, input_param in self._inputs[pid].items():
            value = kwargs.get(sanitize(name))
            if value is not None:
                if isinstance(input_param.defaultValue, ComplexData):
                    encoding = input_param.defaultValue.encoding
                    mimetype = input_param.defaultValue.mimeType

                    if isinstance(value, ComplexData):
                        inp = value

                    else:
                        if utils.is_embedded_in_request(self._wps.url, value):
                            # If encoding is None, this will return the actual encoding used (utf-8 or base64).
                            value, encoding = embed(value, mimetype, encoding=encoding)
                        else:
                            value = fix_url(value)

                        inp = utils.to_owslib(value,
                                              data_type=input_param.dataType,
                                              encoding=encoding,
                                              mimetype=mimetype)

                else:
                    inp = utils.to_owslib(value, data_type=input_param.dataType)

                wps_inputs.append((name, inp))

        wps_outputs = [
            (o.identifier, "ComplexData" in o.dataType)
            for o in self._outputs[pid].values()
        ]

        mode = self._mode if self._processes[pid].storeSupported else SYNC

        try:
            wps_response = self._wps.execute(
                pid, inputs=wps_inputs, output=wps_outputs, mode=mode
            )

            if self._interactive and self._processes[pid].statusSupported:
                if self._notebook:
                    notebook.monitor(wps_response, sleep=.2)
                else:
                    self._console_monitor(wps_response)

        except ServiceException as e:
            if "AccessForbidden" in str(e):
                raise UnauthorizedException(
                    "You are not authorized to do a request of type: Execute"
                )
            raise

        # Add the convenience methods of WPSResult to the WPSExecution class. This adds a `get` method.
        utils.extend_instance(wps_response, WPSResult)
        wps_response.attach(wps_outputs=self._outputs[pid], converters=self._converters)
        return wps_response
Esempio n. 6
0
def nb_form(wps, pid):
    """Return a Notebook form to enter input values and launch process."""
    if wps._notebook:
        return notebook.interact(
            func=getattr(wps, sanitize(pid)),
            inputs=wps._inputs[pid].items())
    else:
        return None
Esempio n. 7
0
def interact(func, inputs):
    """Return a Notebook form to enter input values and launch process.

    The output is stored in the `widget.result` attribute of the response.
    """
    ws = {sanitize(key): input2widget(inpt) for key, inpt in inputs}
    out = widgets.interact_manual(func, **ws)
    out.widget.children[-2].description = 'Launch process'
    # IPython.display.display(out)
    return out
Esempio n. 8
0
 def output_format_widget_values(self, widgets):
     """Return the `output_formats` dict from output_formats widgets."""
     out = {}
     for key, val in widgets.items():
         utils.add_output_format(out,
                                 output_identifier=sanitize(key),
                                 mimetype=val.value,
                                 as_ref=True)
     if out:
         return out
     return {}
Esempio n. 9
0
def test_sanitize():
    assert utils.sanitize('output') == 'output'
    assert utils.sanitize('My Output 1') == 'my_output_1'
    assert utils.sanitize('a.b') == 'a_b'
    assert utils.sanitize('a-b') == 'a_b'
    assert utils.sanitize('return') == 'return_'
    assert utils.sanitize('Finally') == 'finally_'
Esempio n. 10
0
def test_sanitize():  # noqa: D103
    assert utils.sanitize("output") == "output"
    assert utils.sanitize("My Output 1") == "my_output_1"
    assert utils.sanitize("a.b") == "a_b"
    assert utils.sanitize("a-b") == "a_b"
    assert utils.sanitize("return") == "return_"
    assert utils.sanitize("Finally") == "finally_"
Esempio n. 11
0
    def _build_inputs(self, pid, **kwargs):
        """Build the input sequence from the function arguments."""
        wps_inputs = []
        for name, input_param in list(self._inputs[pid].items()):
            arg = kwargs.get(sanitize(name))
            if arg is None:
                continue

            values = (
                [
                    arg,
                ]
                if not isinstance(arg, (list, tuple))
                else arg
            )
            supported_mimetypes = [v.mimeType for v in input_param.supportedValues]

            for value in values:
                #  if input_param.dataType == "ComplexData": seems simpler
                if isinstance(input_param.defaultValue, ComplexData):

                    # Guess the mimetype of the input value
                    mimetype, encoding = guess_type(value, supported_mimetypes)

                    if encoding is None:
                        encoding = input_param.defaultValue.encoding

                    if isinstance(value, ComplexData):
                        inp = value

                    # Either embed the file content or just the reference.
                    else:
                        if utils.is_embedded_in_request(self._wps.url, value):
                            # If encoding is None, this will return the actual encoding used (utf-8 or base64).
                            value, encoding = embed(value, mimetype, encoding=encoding)
                        else:
                            value = fix_url(str(value))

                        inp = utils.to_owslib(
                            value,
                            data_type=input_param.dataType,
                            encoding=encoding,
                            mimetype=mimetype,
                        )

                else:
                    inp = utils.to_owslib(value, data_type=input_param.dataType)

                wps_inputs.append((name, inp))

        return wps_inputs
Esempio n. 12
0
    def __init__(self, func):
        self.result = None
        wps = func.__self__
        pid = self.pid = [
            k for k in wps._processes.keys() if sanitize(k) == func.__name__
        ][0]

        self.process = wps._processes[pid]
        inputs = list(wps._inputs[pid].items())
        outputs = list(wps._outputs[pid].items())

        # Create widgets
        iw = self.input_widgets(inputs)
        ofw = self.output_formats_widgets(outputs)
        go = widgets.Button(
            description="Launch process",
            layout=widgets.Layout(width="100%"),
            button_style="success",
        )
        out = widgets.Output()

        # Interaction logic
        def execute(change):
            """Execute callback when "Launch process" button is clicked."""
            go.disabled = True
            of = self.output_format_widget_values(ofw)
            if of:
                of = {"output_formats": of}
            kwargs = {**self.input_widget_values(iw), **of}

            with out:
                self.result = func(**kwargs)

        # Connect callback to button
        go.on_click(execute)

        # Create GUI
        ui = self.build_ui(iw, ofw, go)
        IPython.display(ui, out)
Esempio n. 13
0
 def _make_output(self, convert_objects=False):
     Output = namedtuple(sanitize(self.process.identifier) + 'Response', [sanitize(o.identifier) for o in
                                                                          self.processOutputs])
     Output.__repr__ = utils.pretty_repr
     return Output(*[self._process_output(o, convert_objects) for o in self.processOutputs])
Esempio n. 14
0
def test_sanitize():
    assert utils.sanitize('output') == 'output'
    assert utils.sanitize('My Output 1') == 'my_output_1'
    assert utils.sanitize('a.b') == 'a_b'
    assert utils.sanitize('a-b') == 'a_b'
Esempio n. 15
0
    def __init__(
        self,
        url,
        processes=None,
        converters=None,
        username=None,
        password=None,
        headers=None,
        verify=True,
        cert=None,
        verbose=False,
        progress=False,
        version=WPS_DEFAULT_VERSION,
    ):
        """
        Args:
            url (str): Link to WPS provider. config (Config): an instance
            processes: Specify a subset of processes to bind. Defaults to all
                processes.
            converters (dict): Correspondence of {mimetype: class} to convert
                this mimetype to a python object.
            username (str): passed to :class:`owslib.wps.WebProcessingService`
            password (str): passed to :class:`owslib.wps.WebProcessingService`
            headers (str): passed to :class:`owslib.wps.WebProcessingService`
            verify (bool): passed to :class:`owslib.wps.WebProcessingService`
            cert (str): passed to :class:`owslib.wps.WebProcessingService`
            verbose (str): passed to :class:`owslib.wps.WebProcessingService`
            progress (bool): If True, enable interactive user mode.
            version (str): WPS version to use.
        """
        self._converters = converters
        self._interactive = progress
        self._mode = ASYNC if progress else SYNC
        self._notebook = notebook.is_notebook()
        self._inputs = {}
        self._outputs = {}

        if not verify:
            import urllib3

            urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

        self._wps = WebProcessingService(
            url,
            version=version,
            username=username,
            password=password,
            verbose=verbose,
            headers=headers,
            verify=verify,
            cert=cert,
            skip_caps=True,
        )

        try:
            self._wps.getcapabilities()
        except ServiceException as e:
            if "AccessForbidden" in str(e):
                raise UnauthorizedException(
                    "You are not authorized to do a request of type: GetCapabilities"
                )
            raise

        self._processes = self._get_process_description(processes)

        # Build the methods
        for pid in self._processes:
            setattr(self, sanitize(pid),
                    types.MethodType(self._method_factory(pid), self))

        self.logger = logging.getLogger('WPSClient')
        if progress:
            self._setup_logging()

        self.__doc__ = utils.build_wps_client_doc(self._wps, self._processes)
Esempio n. 16
0
    def __init__(
        self,
        url,
        processes=None,
        converters=None,
        username=None,
        password=None,
        headers=None,
        verify=True,
        cert=None,
        verbose=False,
        progress=False,
        version=WPS_DEFAULT_VERSION,
    ):
        """
        Args:
            url (str): Link to WPS provider. config (Config): an instance
            processes: Specify a subset of processes to bind. Defaults to all
                processes.
            converters (dict): Correspondence of {mimetype: class} to convert
                this mimetype to a python object.
            username (str): passed to :class:`owslib.wps.WebProcessingService`
            password (str): passed to :class:`owslib.wps.WebProcessingService`
            headers (str): passed to :class:`owslib.wps.WebProcessingService`
            verify (bool): passed to :class:`owslib.wps.WebProcessingService`
            cert (str): passed to :class:`owslib.wps.WebProcessingService`
            verbose (str): passed to :class:`owslib.wps.WebProcessingService`
            progress (bool): If True, enable interactive user mode.
            version (str): WPS version to use.
        """
        self._converters = converters
        self._interactive = progress
        self._mode = ASYNC if progress else SYNC
        self._notebook = notebook.is_notebook()
        self._inputs = {}
        self._outputs = {}

        if not verify:
            import urllib3

            urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

        self._wps = WebProcessingService(
            url,
            version=version,
            username=username,
            password=password,
            verbose=verbose,
            headers=headers,
            verify=verify,
            cert=cert,
            skip_caps=True,
        )

        try:
            self._wps.getcapabilities()
        except ServiceException as e:
            if "AccessForbidden" in str(e):
                raise UnauthorizedException(
                    "You are not authorized to do a request of type: GetCapabilities"
                )
            raise

        self._processes = self._get_process_description(processes)

        # Build the methods
        for pid in self._processes:
            setattr(self, sanitize(pid), types.MethodType(self._method_factory(pid), self))

        self.logger = logging.getLogger('WPSClient')
        if progress:
            self._setup_logging()

        self.__doc__ = utils.build_wps_client_doc(self._wps, self._processes)
Esempio n. 17
0
    def __init__(
        self,
        url,
        processes=None,
        converters=None,
        username=None,
        password=None,
        headers=None,
        auth=None,
        verify=True,
        cert=None,
        verbose=False,
        progress=False,
        version=WPS_DEFAULT_VERSION,
        caps_xml=None,
        desc_xml=None,
        language=None,
    ):
        """
        Args:
            url (str): Link to WPS provider. config (Config): an instance
            processes: Specify a subset of processes to bind. Defaults to all
                processes.
            converters (dict): Correspondence of {mimetype: class} to convert
                this mimetype to a python object.
            username (str): passed to :class:`owslib.wps.WebProcessingService`
            password (str): passed to :class:`owslib.wps.WebProcessingService`
            headers (str): passed to :class:`owslib.wps.WebProcessingService`
            auth (requests.auth.AuthBase): requests-style auth class to authenticate,
                see https://2.python-requests.org/en/master/user/authentication/
            verify (bool): passed to :class:`owslib.wps.WebProcessingService`
            cert (str): passed to :class:`owslib.wps.WebProcessingService`
            verbose (str): passed to :class:`owslib.wps.WebProcessingService`
            progress (bool): If True, enable interactive user mode.
            version (str): WPS version to use.
            language (str): passed to :class:`owslib.wps.WebProcessingService`
                ex: 'fr-CA', 'en_US'.
        """
        self._converters = converters
        self._interactive = progress
        self._mode = ASYNC if progress else SYNC
        self._notebook = notebook.is_notebook()
        self._inputs = {}
        self._outputs = {}

        if not verify:
            import urllib3

            urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

        if headers is None:
            headers = {}

        if auth is not None:
            if isinstance(auth, tuple) and len(auth) == 2:
                # special-case basic HTTP auth
                auth = requests.auth.HTTPBasicAuth(*auth)

            # We only need some headers from the requests.auth.AuthBase implementation
            # We prepare a dummy request, call the auth object with it, and get its headers
            dummy_request = requests.Request("get", "http://localhost")
            r = auth(dummy_request.prepare())

            auth_headers = ["Authorization", "Proxy-Authorization", "Cookie"]
            headers.update(
                {h: r.headers[h]
                 for h in auth_headers if h in r.headers})

        self._wps = WebProcessingService(url,
                                         version=version,
                                         username=username,
                                         password=password,
                                         verbose=verbose,
                                         headers=headers,
                                         verify=verify,
                                         cert=cert,
                                         skip_caps=True,
                                         language=language)

        try:
            self._wps.getcapabilities(xml=caps_xml)
        except ServiceException as e:
            if "AccessForbidden" in str(e):
                raise UnauthorizedException(
                    "You are not authorized to do a request of type: GetCapabilities"
                )
            raise

        self._processes = self._get_process_description(processes,
                                                        xml=desc_xml)

        # Build the methods
        for pid in self._processes:
            setattr(self, sanitize(pid),
                    types.MethodType(self._method_factory(pid), self))

        self.logger = logging.getLogger('WPSClient')
        if progress:
            self._setup_logging()

        self.__doc__ = utils.build_wps_client_doc(self._wps, self._processes)
Esempio n. 18
0
 def input_widgets(self, inputs):
     """Return input parameter widgets."""
     return {sanitize(key): input2widget(inpt) for key, inpt in inputs}
Esempio n. 19
0
    def _execute(self, pid, **kwargs):
        """Execute the process."""
        wps_inputs = []
        for name, input_param in self._inputs[pid].items():
            value = kwargs.get(sanitize(name))
            if value is not None:
                if isinstance(input_param.defaultValue, ComplexData):
                    encoding = input_param.defaultValue.encoding
                    mimetype = input_param.defaultValue.mimeType

                    if isinstance(value, ComplexData):
                        inp = value

                    else:
                        if utils.is_embedded_in_request(self._wps.url, value):
                            # If encoding is None, this will return the actual encoding used (utf-8 or base64).
                            value, encoding = embed(value,
                                                    mimetype,
                                                    encoding=encoding)
                        else:
                            value = fix_url(value)

                        inp = utils.to_owslib(value,
                                              data_type=input_param.dataType,
                                              encoding=encoding,
                                              mimetype=mimetype)

                else:
                    inp = utils.to_owslib(value,
                                          data_type=input_param.dataType)

                wps_inputs.append((name, inp))

        wps_outputs = [(o.identifier, "ComplexData" in o.dataType)
                       for o in self._outputs[pid].values()]

        mode = self._mode if self._processes[pid].storeSupported else SYNC

        try:
            wps_response = self._wps.execute(pid,
                                             inputs=wps_inputs,
                                             output=wps_outputs,
                                             mode=mode)

            if self._interactive and self._processes[pid].statusSupported:
                if self._notebook:
                    notebook.monitor(wps_response, sleep=.2)
                else:
                    self._console_monitor(wps_response)

        except ServiceException as e:
            if "AccessForbidden" in str(e):
                raise UnauthorizedException(
                    "You are not authorized to do a request of type: Execute")
            raise

        # Add the convenience methods of WPSResult to the WPSExecution class. This adds a `get` method.
        utils.extend_instance(wps_response, WPSResult)
        wps_response.attach(wps_outputs=self._outputs[pid],
                            converters=self._converters)
        return wps_response
Esempio n. 20
0
def test_sanitize():
    assert utils.sanitize('output') == 'output'
    assert utils.sanitize('My Output 1') == 'my_output_1'
    assert utils.sanitize('a.b') == 'a_b'
    assert utils.sanitize('a-b') == 'a_b'