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
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
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))
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)
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
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)
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
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)
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
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)
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))
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')
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")
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))
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
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
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")
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
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
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
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)