Esempio n. 1
0
def parse_layer_spec(layerspec: str,
                     context: ProcessingContext,
                     allow_selection: bool = False) -> Tuple[str, bool]:
    """ Parse a layer specification

        if allow_selection is set to True: 'select' parameter
        is interpreted has holding a qgis feature request expression

        :return: A tuple (path, bool)
    """
    u = urlparse(layerspec)
    p = u.path
    if u.scheme == 'file':
        p = context.resolve_path(p)
    elif u.scheme and u.scheme != 'layer':
        raise InvalidParameterValue("Bad scheme: %s" % layerspec)

    if not allow_selection:
        return p, False

    has_selection = False
    qs = parse_qs(u.query)
    feat_requests = qs.get('select', [])
    feat_rects = qs.get('rect', [])
    if feat_rects or feat_requests:
        has_selection = True
        layer = context.getMapLayer(p)
        if not layer:
            LOGGER.error("No layer path for url %s", u)
            raise InvalidParameterValue("No layer '%s' found" % u.path, )

        if layer.type() != QgsMapLayer.VectorLayer:
            LOGGER.warning("Can apply selection only to vector layer")
        else:
            behavior = QgsVectorLayer.SetSelection
            try:
                LOGGER.debug("Applying features selection: %s", qs)
                # Apply filter rect first
                if feat_rects:
                    rect = QgsRectangle(feat_rects[-1].split(',')[:4])
                    layer.selectByRect(rect, behavior=behavior)
                    behavior = QgsVectorLayer.IntersectSelection
                # Selection by expressions
                if feat_requests:
                    ftreq = feat_requests[-1]
                    layer.selectByExpression(ftreq, behavior=behavior)
            except:
                LOGGER.error(traceback.format_exc())
                raise NoApplicableCode("Feature selection failed")
    return p, has_selection
Esempio n. 2
0
    def describe(self, identifiers, **context):
        """ Return process description
        """
        if not identifiers:
            raise MissingParameterValue('', 'identifier')

        # 'all' keyword means all processes
        if 'all' in (ident.lower() for ident in identifiers):
            identifiers = [p.identifier for p in self.processes]

        identifier_elements = []
        try:
            identifier_elements.extend(
                p.describe_xml()
                for p in self.get_processes(identifiers, **context))
        except UnknownProcessError as exc:
            raise InvalidParameterValue("Unknown process %s" % exc,
                                        "identifier")
        except Exception as e:
            LOGGER.critical("Exception:\n%s", traceback.format_exc())
            raise NoApplicableCode(str(e), code=500)

        doc = WPS.ProcessDescriptions(*identifier_elements)
        doc.attrib['{http://www.w3.org/2001/XMLSchema-instance}schemaLocation'] = \
            'http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsDescribeProcess_response.xsd'
        doc.attrib['service'] = 'WPS'
        doc.attrib['version'] = '1.0.0'
        doc.attrib['{http://www.w3.org/XML/1998/namespace}lang'] = 'en-US'
        return doc
Esempio n. 3
0
 def _check_valid(self):
     """Validate this input usig given validator
     """
     validate = self.validator
     _valid = validate(self, self.valid_mode)
     if not _valid:
         raise InvalidParameterValue('Input data not valid using '
                                     'mode %s' % (self.valid_mode))
Esempio n. 4
0
 def check_and_set_timeout(self, timeout):
     try:
         if timeout is not None:
             _timeout = int(timeout)
             if _timeout <= 0:
                 raise ValueError()
             self.timeout = min(self.timeout, _timeout)
     except ValueError:
         raise InvalidParameterValue('TIMEOUT param must be an integer > 0 value, not "%s"', timeout)
Esempio n. 5
0
def convert_positiveInteger(inpt: LiteralInputValue) -> int:
    """Return value of input"""

    inpt = convert_integer(inpt)
    if inpt < 0:
        raise InvalidParameterValue(
            'The value "{}" is not of type positiveInteger'.format(inpt))
    else:
        return inpt
Esempio n. 6
0
 def check_and_set_expiration(self, expire):
     try:
         if expire is not None:
             _expire = int(expire)
             if _expire <= 0:
                 raise ValueError()
             self.expiration = _expire
     except ValueError:
         raise InvalidParameterValue('EXPIRE param must be an integer > 0 value, not "%s"', expire)
Esempio n. 7
0
 def get_processes_for_request(self, idents: Iterable[str], 
                               map_uri: Optional[str]=None) -> Iterable[WPSProcess]:
     try:
         return self.get_processes(idents, map_uri)
     except UnknownProcessError as exc:
         raise InvalidParameterValue("Unknown process %s" % exc, "identifier") from None
     except Exception as e:
         LOGGER.critical("Exception:\n%s",traceback.format_exc())
         raise NoApplicableCode(str(e), code=500) from None
Esempio n. 8
0
    async def get(self):
        """ Handle Get Method
        """
        service = self.get_argument('SERVICE')
        if service.lower() != 'wps':
            raise InvalidParameterValue(
                'parameter SERVICE [%s] not supported' % service, 'service')

        document = await self.handle_wps_request(OWSRequest.parse_get_request)

        self.write_xml(document)
Esempio n. 9
0
    def check_and_set_language(self, language):
        """set this.language
        """

        if not language:
            language = 'None'
        elif language != 'en-US':
            raise InvalidParameterValue(
                'The requested language "%s" is not supported by this server' % language, 'language')
        else:
            self.language = language
Esempio n. 10
0
def parse_literal_input(param: QgsProcessingParameterDefinition,
                        kwargs) -> LiteralInput:
    """
    """
    typ = param.type()

    if typ == 'string':
        kwargs['data_type'] = 'string'
    elif typ == 'boolean':
        kwargs['data_type'] = 'boolean'
    elif typ == 'enum':
        options = param.options()
        kwargs['data_type'] = 'string'
        kwargs['allowed_values'] = options
        kwargs['max_occurs'] = len(options) if param.allowMultiple() else 1
        default_value = param.defaultValue()
        if default_value is not None:
            # XXX Values for processing enum are indices
            if isinstance(default_value, int):
                kwargs['default'] = options[default_value]
            elif isinstance(default_value, list):
                kwargs['default'] = options[default_value[0]]
            else:
                raise InvalidParameterValue('Unsupported default value: %s' %
                                            default_value)
    elif typ == 'number':
        kwargs['data_type'] = {
            QgsProcessingParameterNumber.Double: 'float',
            QgsProcessingParameterNumber.Integer: 'integer'
        }[param.dataType()]
        kwargs['allowed_values'] = [(param.minimum(), param.maximum())]
    elif typ == 'field':
        kwargs['data_type'] = 'string'
        kwargs['metadata'].append(
            Metadata('processing:parentLayerParameterName',
                     param.parentLayerParameterName()))
        kwargs['metadata'].append(
            Metadata(
                'processing:dataType', {
                    QgsProcessingParameterField.Any: 'Any',
                    QgsProcessingParameterField.Numeric: 'Numeric',
                    QgsProcessingParameterField.String: 'String',
                    QgsProcessingParameterField.DateTime: 'DateTime'
                }[param.dataType()]))
    elif typ == 'crs':
        kwargs['data_type'] = 'string'
    elif typ == 'band':
        kwargs['data_type'] = 'nonNegativeInteger'
    else:
        return None

    return LiteralInput(**kwargs)
Esempio n. 11
0
def convert(data_type: str, data: LiteralInputValue) -> Any:
    """function for decoration of convert
    """
    convert = None
    if data_type in LITERAL_DATA_TYPES:
        if data_type == 'string':
            convert = convert_string
        elif data_type == 'integer':
            convert = convert_integer
        elif data_type == 'float':
            convert = convert_float
        elif data_type == 'boolean':
            convert = convert_boolean
        elif data_type == 'positiveInteger':
            convert = convert_positiveInteger
        elif data_type == 'anyURI':
            convert = convert_anyURI
        elif data_type == 'time':
            convert = convert_time
        elif data_type == 'date':
            convert = convert_date
        elif data_type == 'dateTime':
            convert = convert_datetime
        elif data_type == 'scale':
            convert = convert_scale
        elif data_type == 'angle':
            convert = convert_angle
        elif data_type == 'nonNegativeInteger':
            convert = convert_positiveInteger
        else:
            raise InvalidParameterValue(
                "Invalid data_type value of LiteralInput " + \
                "set to '{}'".format(data_type))
    try:
        return convert(data)
    except ValueError:
        raise InvalidParameterValue(
            "Could not convert value '{}' to format '{}'".format(
                data, data_type))
Esempio n. 12
0
 def data_format(self, data_format):
     """self data_format setter
     """
     if self._is_supported(data_format):
         self._data_format = data_format
         if not data_format.validate or data_format.validate == emptyvalidator:
             data_format.validate = get_validator(data_format.mime_type)
     else:
         raise InvalidParameterValue(
             "Requested format "
             "%s, %s, %s not supported" %
             (data_format.mime_type, data_format.encoding,
              data_format.schema), 'mimeType')
Esempio n. 13
0
def wkt_to_geometry(wkt: str) -> Geometry:
    """ Convert wkt to qgis geometry

        Handle CRS= prefix
    """
    m = WKT_EXPR.match(wkt)
    if m:
        g = QgsGeometry.fromWkt(m.groups('')[1])
        if not g.isNull():
            crs = QgsCoordinateReferenceSystem(m.groups('')[0])
            if crs.isValid():
                g = QgsReferencedGeometry(g, crs)
        return g
    raise InvalidParameterValue("Invalid wkt format")
Esempio n. 14
0
def convert_anyURI(inpt: LiteralInputValue) -> str:
    """Return value of input

    :rtype: url components
    """

    inpt = convert_string(inpt)
    components = urlparse(inpt)

    if components[0] and components[1]:
        return components.geturl()
    else:
        raise InvalidParameterValue(
            'The value "{}" does not seem to be of type anyURI'.format(inpt))
Esempio n. 15
0
    async def execute(self, identifier, wps_request, uuid, **context):
        """Parse and perform Execute WPS request call
        
        :param identifier: process identifier string
        :param wps_request: pyqgiswps.WPSRequest structure with parsed inputs, still in memory
        :param uuid: string identifier of the request
        """
        try:
            process = self.get_process(identifier, **context)
        except UnknownProcessError:
            raise InvalidParameterValue("Unknown process '%r'" % identifier,
                                        'Identifier')

        # make deep copy of the process instance
        # so that processes are not overriding each other
        # just for execute
        process = copy.deepcopy(process)

        self._parse(process, wps_request)

        workdir = os.path.abspath(confservice.get('server', 'workdir'))
        workdir = os.path.join(workdir, str(uuid))

        # Create working directory if it does not exists
        os.makedirs(workdir, exist_ok=True)

        process.set_workdir(workdir)

        # Get status url
        status_url = self._status_url(uuid, wps_request)

        # Create response object
        wps_response = WPSResponse(process,
                                   wps_request,
                                   uuid,
                                   status_url=status_url)

        if wps_request.store_execute == 'true':
            # Setting STORE_AND_UPDATE_STATUS will trigger
            # asynchronous requests
            wps_response.status = STATUS.STORE_AND_UPDATE_STATUS
            LOGGER.debug("Update status enabled")

        if wps_request.raw:
            raise NotImplementedError("Raw output is not implemented")

        document = await self.executor.execute(wps_request, wps_response)

        return document
Esempio n. 16
0
def gml_to_geometry(gml: str) -> Geometry:
    """ Handle json to qgis geometry
    """
    # Lookup for srsName
    geom = ogr.CreateGeometryFromGML(gml)
    if not geom:
        raise InvalidParameterValue("Invalid gml format")

    geom = QgsGeometry.fromWkt(geom.ExportToWkt())
    # Check for crs
    m = SRSNAME_EXPR.search(gml)
    if m:
        crs = QgsCoordinateReferenceSystem(m.groups('')[0])
        if crs.isValid():
            geom = QgsReferencedGeometry(geom, crs)
    return geom
Esempio n. 17
0
def json_to_geometry(data: str) -> Geometry:
    """ Handle json to qgis geometry
    """
    try:
        data = json.loads(data)
        crs = data.get('crs')
        if crs:
            crs = QgsCoordinateReferenceSystem(crs['properties']['name'])
            data = data['geometry']
        geom = ogr.CreateGeometryFromJson(json.dumps(data))
        if geom:
            geom = QgsGeometry.fromWkt(geom.ExportToWkt())
            if crs and crs.isValid():
                geom = QgsReferencedGeometry(geom, crs)
            return geom
    except (json.JSONDecodeError, KeyError) as err:
        LOGGER.error("Error decoding json input: %s", err)

    raise InvalidParameterValue("Invalid geojson format")
Esempio n. 18
0
    def create_complex_inputs(self, source: ComplexInput, 
                              inputs: Iterable[JsonValue]) -> Iterable[ComplexInput]:
        """ Create new ComplexInput as clone of original ComplexInput

            because of inputs can be more then one, take it just as Prototype
            :return collections.deque:
        """
        outinputs = deque(maxlen=source.max_occurs)

        for inpt in inputs:
            data_input = source.clone()
            frmt = data_input.supported_formats[0]
            if 'mimeType' in inpt:
                if inpt['mimeType']:
                    frmt = data_input.get_format(inpt['mimeType'])
                else:
                    frmt = data_input.data_format

            if frmt:
                data_input.data_format = frmt
            else:
                raise InvalidParameterValue(
                    'Invalid mimeType value %s for input %s' %
                    (inpt.get('mimeType'), source.identifier),
                    'mimeType')

            # get the referenced input otherwise get the value of the field
            href = inpt.get('href', None)
            if href:
                data_input.method = inpt.get('method', 'GET')
                data_input.url = href
                data_input.as_reference = True
                data_input.body = inpt.get('body',None)
            else:
                data_input.data = inpt.get('data')

            outinputs.append(data_input)
        if len(outinputs) < source.min_occurs:
            raise MissingParameterValue(description="Given data input is missing", locator=source.identifier)
        return outinputs
Esempio n. 19
0
    def parse_get_request(handler):
        """ HTTP GET request parser

            :return: A WPSRequest instance
        """
        service = handler.get_argument('SERVICE')
        if service.lower() != 'wps':
            raise InvalidParameterValue(
                'parameter SERVICE [%s] not supported' % service, 'SERVICE')

        operation = handler.get_argument('REQUEST').lower()

        wpsrequest = WPSRequest()

        _get_query_param = handler.get_argument

        def parse_get_getresults():
            """ Parse GET GetResults
            """
            wpsrequest.results_uuid = _get_query_param('UUID')

        def parse_get_getcapabilities():
            """Parse GET GetCapabilities request
            """
            acceptedversions = _get_query_param('ACCEPTVERSIONS', None)
            wpsrequest.check_accepted_versions(acceptedversions)

        def parse_get_describeprocess():
            """Parse GET DescribeProcess request
            """
            version = _get_query_param('VERSION', None)
            wpsrequest.check_and_set_version(version)

            language = _get_query_param('LANGUAGE', None)
            wpsrequest.check_and_set_language(language)

            wpsrequest.identifiers = _get_query_param('IDENTIFIER').split(',')

        def parse_get_execute():
            """Parse GET Execute request
            """
            version = _get_query_param('VERSION', None)
            wpsrequest.check_and_set_version(version)

            language = _get_query_param('LANGUAGE', None)
            wpsrequest.check_and_set_language(language)

            wpsrequest.identifier = _get_query_param('IDENTIFIER')

            timeout = _get_query_param('TIMEOUT', None)
            wpsrequest.check_and_set_timeout(timeout)

            expire = _get_query_param('EXPIRE', None)
            wpsrequest.check_and_set_expiration(expire)

            wpsrequest.store_execute = _get_query_param(
                'STOREEXECUTERESPONSE', 'false')
            # XXX If storeExecuteResponse is set to true then we enforce
            # status supports. This will trigger *asynchronous* request.
            wpsrequest.status = wpsrequest.store_execute
            wpsrequest.lineage = _get_query_param('LINEAGE', 'false')

            wpsrequest.inputs = get_data_from_kvp(
                _get_query_param('DATAINPUTS', None), 'DataInputs')
            wpsrequest.outputs = {}

            # take responseDocument preferably
            resp_outputs = get_data_from_kvp(
                _get_query_param('RESPONSEDOCUMENT', None))
            raw_outputs = get_data_from_kvp(
                _get_query_param('RAWDATAOUTPUT', None))
            wpsrequest.raw = False
            if resp_outputs:
                wpsrequest.outputs = resp_outputs
            elif raw_outputs:
                wpsrequest.outputs = raw_outputs
                wpsrequest.raw = True
                # executeResponse XML will not be stored and no updating of
                # status
                wpsrequest.store_execute = 'false'
                wpsrequest.status = 'false'

        wpsrequest.operation = operation

        if operation == 'getresults':
            parse_get_getresults()
        elif operation == 'getcapabilities':
            parse_get_getcapabilities()
        elif operation == 'describeprocess':
            parse_get_describeprocess()
        elif operation == 'execute':
            parse_get_execute()
        else:
            raise OperationNotSupported('Unknown request %r' % operation,
                                        operation)

        # Return the created WPSRequest object
        return wpsrequest
Esempio n. 20
0
    def parse_post_request(handler):
        """Factory function returing propper parsing function
        """
        try:
            doc = lxml.etree.fromstring(handler.request.body)
        except Exception as e:
            raise NoApplicableCode(e.msg)

        wpsrequest = WPSRequest()

        tagname = doc.tag

        def parse_post_getcapabilities():
            """Parse POST GetCapabilities request
            """
            acceptedversions = xpath_ns(
                doc, '/wps:GetCapabilities/ows:AcceptVersions/ows:Version')
            acceptedversions = ','.join(map(lambda v: v.text,
                                            acceptedversions))
            wpsrequest.check_accepted_versions(acceptedversions)

        def parse_post_describeprocess():
            """Parse POST DescribeProcess request
            """

            version = doc.attrib.get('version')
            wpsrequest.check_and_set_version(version)

            language = doc.attrib.get('language')
            wpsrequest.check_and_set_language(language)

            wpsrequest.operation = 'describeprocess'
            wpsrequest.identifiers = [
                identifier_el.text
                for identifier_el in xpath_ns(doc, './ows:Identifier')
            ]

        def parse_post_execute():
            """Parse POST Execute request
            """

            version = doc.attrib.get('version')
            wpsrequest.check_and_set_version(version)

            language = doc.attrib.get('language')
            wpsrequest.check_and_set_language(language)

            wpsrequest.operation = 'execute'

            identifier = xpath_ns(doc, './ows:Identifier')

            if not identifier:
                raise MissingParameterValue('Process identifier not set',
                                            'Identifier')

            wpsrequest.identifier = identifier[0].text
            wpsrequest.lineage = 'false'
            wpsrequest.store_execute = 'false'
            wpsrequest.status = 'false'
            wpsrequest.inputs = get_inputs_from_xml(doc)
            wpsrequest.outputs = get_output_from_xml(doc)
            wpsrequest.raw = False
            if xpath_ns(doc,
                        '/wps:Execute/wps:ResponseForm/wps:RawDataOutput'):
                wpsrequest.raw = True
                # executeResponse XML will not be stored
                wpsrequest.store_execute = 'false'

            # check if response document tag has been set then retrieve
            response_document = xpath_ns(
                doc, './wps:ResponseForm/wps:ResponseDocument')
            if len(response_document) > 0:
                wpsrequest.lineage = response_document[0].attrib.get(
                    'lineage', 'false')
                wpsrequest.store_execute = response_document[0].attrib.get(
                    'storeExecuteResponse', 'false')
                # XXX If storeExecuteResponse is set then we enforce
                # the status supports
                wpsrequest.status = wpsrequest.store_execute
                # Set timeout
                timeout = response_document[0].attrib.get('timeout')
                wpsrequest.check_and_set_timeout(timeout)
                # Set expiration
                expire = response_document[0].attrib.get('expire')
                wpsrequest.check_and_set_expiration(expire)

        if tagname == WPS.GetCapabilities().tag:
            wpsrequest.operation = 'getcapabilities'
            parse_post_getcapabilities()
        elif tagname == WPS.DescribeProcess().tag:
            wpsrequest.operation = 'describeprocess'
            parse_post_describeprocess()
        elif tagname == WPS.Execute().tag:
            wpsrequest.operation = 'execute'
            parse_post_execute()
        else:
            raise InvalidParameterValue('Unknown request %r' % tagname,
                                        'request')

        # Return the created WPSRequest object
        return wpsrequest
Esempio n. 21
0
def parse_literal_input(param: QgsProcessingParameterDefinition,
                        kwargs) -> LiteralInput:
    """ Convert processing input to Literal Input 
    """
    typ = param.type()

    if typ == 'string':
        kwargs['data_type'] = 'string'
    elif typ == 'boolean':
        kwargs['data_type'] = 'boolean'
    elif typ == 'enum':
        options = param.options()
        kwargs['data_type'] = 'string'
        kwargs['allowed_values'] = options
        kwargs['max_occurs'] = len(options) if param.allowMultiple() else 1
        default_value = param.defaultValue()
        if default_value is not None:
            # XXX Values for processing enum are indices
            if isinstance(default_value, list):
                default_value = default_value[0]
            if not isinstance(default_value, int):
                raise InvalidParameterValue(
                    'Unsupported default value for parameter %s: %s' %
                    (param.name(), default_value))
            if default_value < 0 or default_value >= len(options):
                LOGGER.error(
                    "Out of range default value for enum parameter %s: %s",
                    param.name(), default_value)
                default_value = 0

            kwargs['default'] = options[default_value]

    elif typ == 'number':
        kwargs['data_type'] = _number_data_type(param)
        kwargs['allowed_values'] = [(param.minimum(), param.maximum())]
    elif typ == 'distance':
        kwargs['data_type'] = 'length'
        kwargs['allowed_values'] = [(param.minimum(), param.maximum())]
        kwargs['metadata'].extend((
            Metadata('processing:parentParameterName',
                     param.parentParameterName()),
            Metadata('processing:defaultUnit',
                     QgsUnitTypes.toString(param.defaultUnit())),
        ))
    elif typ == 'scale':
        kwargs['data_type'] = 'scale'
        kwargs['allowed_values'] = [(param.minimum(), param.maximum())]
    elif typ == 'duration':
        # XXX OGC duration is defined as time dataType
        kwargs['data_type'] = 'time'
        kwargs['allowed_values'] = [(param.minimum(), param.maximum())]
        kwargs['metadata'].append(
            Metadata('processing:defaultUnit',
                     QgsUnitTypes.toString(param.defaultUnit())), )
    elif typ == 'field':
        kwargs['data_type'] = 'string'
        kwargs['metadata'].append(
            Metadata('processing:parentLayerParameterName',
                     param.parentLayerParameterName()))
        kwargs['metadata'].append(
            Metadata(
                'processing:dataType', {
                    QgsProcessingParameterField.Any: 'Any',
                    QgsProcessingParameterField.Numeric: 'Numeric',
                    QgsProcessingParameterField.String: 'String',
                    QgsProcessingParameterField.DateTime: 'DateTime',
                }[param.dataType()]))
    elif typ == 'band':
        kwargs['data_type'] = 'nonNegativeInteger'
    else:
        return None

    return LiteralInput(**kwargs)