def parse_input_definition(param: QgsProcessingParameterDefinition, kwargs) -> Union[LiteralInput, ComplexInput]: """ Convert processing input to File Input """ typ = param.type() if typ == 'file': if param.behavior() == QgsProcessingParameterFile.Folder: kwargs['data_type'] = 'string' return LiteralInput(**kwargs) ext = param.extension() if ext: mime = mimetypes.types_map.get(ext) if mime is not None: kwargs['supported_formats'] = [Format(mime)] kwargs['metadata'].append( Metadata('processing:extension', param.extension())) return ComplexInput(**kwargs) elif typ == 'fileDestination': extension = '.' + param.defaultFileExtension() kwargs['data_type'] = 'string' kwargs['metadata'].append( Metadata('processing:format', mimetypes.types_map.get(extension, ''))) return LiteralInput(**kwargs) elif typ == 'folderDestination': kwargs['data_type'] = 'string' return LiteralInput(**kwargs)
def get_processing_value(param: QgsProcessingParameterDefinition, inp: WPSInput, context: ProcessingContext) -> Any: """ Return processing value from wps inputs Processes other inputs than layers """ typ = param.type() if typ in ('fileDestination', 'folderDestination'): # Normalize path value = basename(normpath(inp[0].data)) if value != inp[0].data: LOGGER.warning( "Value for file or folder destination '%s' has been truncated from '%s' to '%s'", param.name(), inp[0].data, value) if typ == 'fileDestination': value = Path(value).with_suffix( '.' + param.defaultFileExtension()).as_posix() elif typ == 'file': # Handle file reference outputfile = (Path(context.workdir) / param.name()).with_suffix( param.extension()) LOGGER.debug("Saving input data as %s", outputfile.as_posix()) inp[0].download_ref(outputfile) value = outputfile.name else: value = None return value
def parse_layer_input(param: QgsProcessingParameterDefinition, kwargs, context: MapContext = None) -> LiteralInput: """ Layers input are passed as layer name We treat layer destination the same as input since they refer to layers ids in qgisProject """ if isinstance(param, INPUT_LAYER_TYPES): kwargs['data_type'] = 'string' parse_allowed_layers(param, kwargs, context) elif isinstance(param, QgsProcessingParameterRasterDestination): kwargs['data_type'] = 'string' kwargs['metadata'].append( Metadata('processing:extension', param.defaultFileExtension())) elif isinstance(param, (QgsProcessingParameterVectorDestination, QgsProcessingParameterFeatureSink)): kwargs['data_type'] = 'string' kwargs['metadata'].append( Metadata('processing:dataType', str(param.dataType()))) kwargs['metadata'].append( Metadata('processing:extension', param.defaultFileExtension())) else: return None return LiteralInput(**kwargs)
def __init__(self, name='', description='', options=[], default=None, isSource=False, multiple=False, optional=False): QgsProcessingParameterDefinition.__init__(self, name, description, default, optional) self.setMetadata({ 'widget_wrapper': { 'class': 'processing.algs.otb.OtbChoiceWidget.OtbChoiceWidgetWrapper' } }) self.options = options if default is not None: try: self.default = int(default) except: self.default = 0 self.value = self.default
def parse_input_definition(param: QgsProcessingParameterDefinition, kwargs, context: MapContext = None) -> WPSInput: """ Convert processing input to File Input """ typ = param.type() if typ == 'crs': kwargs['data_type'] = 'string' return LiteralInput(**kwargs) elif typ == "extent": return parse_extent_input(param, kwargs, context) elif isinstance(param, GeometryParameterTypes): kwargs['supported_formats'] = [ Format.from_definition(FORMATS.GEOJSON), Format.from_definition(FORMATS.GML), Format.from_definition(FORMATS.WKT) ] if isinstance(param, QgsProcessingParameterGeometry): # Add metadata from requiered geometryTypes kwargs['metadata'].extend( Metadata('processing:geometryType', QgsWkbTypes.geometryDisplayString(geomtype)) \ for geomtype in param.geometryTypes() ) if param.allowMultipart(): kwargs['metadata'].append( Metadata('processing:allowMultipart')) return ComplexInput(**kwargs) return None
def parse_allowed_layers(param: QgsProcessingParameterDefinition, kwargs, context: MapContext) -> None: """ Find candidate layers according to datatypes """ typ = param.type() if typ == 'multilayer': num_inputs = param.minimumNumberInputs() kwargs['min_occurs'] = num_inputs if num_inputs >= 1 else 0 kwargs['max_occurs'] = 20 # XXX arbitrary number datatypes = [] if isinstance(param, QgsProcessingParameterLimitedDataTypes): datatypes = param.dataTypes() if not datatypes: if isinstance(param, INPUT_VECTOR_LAYER_TYPES): datatypes = [QgsProcessing.TypeVector] elif isinstance(param, INPUT_RASTER_LAYER_TYPES): datatypes = [QgsProcessing.TypeRaster] elif isinstance(param, QgsProcessingParameterMultipleLayers): datatypes = [param.layerType()] else: datatypes = [QgsProcessing.TypeMapLayer] kwargs['metadata'].append( Metadata('processing:dataTypes', ','.join(SourceTypes[dtyp] for dtyp in datatypes))) # Nothing to do is there is no context if context is None: return project = context.project() def _is_allowed(lyr): if lyr.type() == QgsMapLayer.VectorLayer: geomtype = lyr.geometryType() return (geomtype == QgsWkbTypes.PointGeometry and QgsProcessing.TypeVectorPoint in datatypes) \ or (geomtype == QgsWkbTypes.LineGeometry and QgsProcessing.TypeVectorLine in datatypes) \ or (geomtype == QgsWkbTypes.PolygonGeometry and QgsProcessing.TypeVectorPolygon in datatypes) \ or QgsProcessing.TypeVectorAnyGeometry in datatypes \ or QgsProcessing.TypeVector in datatypes \ or QgsProcessing.TypeMapLayer in datatypes elif lyr.type() == QgsMapLayer.RasterLayer: return QgsProcessing.TypeRaster in datatypes \ or QgsProcessing.TypeMapLayer in datatypes return False kwargs['allowed_values'] = [ lyr.name() for lyr in project.mapLayers().values() if _is_allowed(lyr) ] # Set max occurs accordingly to if typ == 'multilayer': kwargs['max_occurs'] = len(kwargs['allowed_values'])
def parse_input_definition(param: QgsProcessingParameterDefinition, kwargs, context: MapContext = None) -> LiteralInput: """ Layers input may be passed in various forms: - For input layers and if a context is given: it will be a list of available layers from the source project as literal string. - If there is no context, the input will be defined as a complex input for valid gis data. We treat layer destination the same as input since they refer to layers ids in qgisProject """ if isinstance(param, INPUT_LAYER_TYPES): typ = param.type() if typ == 'multilayer': num_inputs = param.minimumNumberInputs() kwargs['min_occurs'] = num_inputs if num_inputs >= 1 else 0 kwargs['max_occurs'] = kwargs['min_occurs'] # Set metadata for geometry type datatypes = get_layers_type(param, kwargs) kwargs['data_type'] = 'string' if context is not None: # Retrieve the list of layers # Inputs will be a list of strings from the source # project get_layers_from_context(kwargs, context, datatypes) # Set max occurs accordingly if typ == 'multilayer': kwargs['max_occurs'] = len(kwargs['allowed_values']) return LiteralInput(**kwargs) elif isinstance(param, DESTINATION_LAYER_TYPES): # Since QgsProcessingOutputLayerDefinition may # be defined as default value, get extension # and layer name from it extension, defval = get_default_destination_values( param, kwargs['default']) kwargs['default'] = defval kwargs['data_type'] = 'string' # Used to retrieve extension when handling wps response kwargs['metadata'].append(Metadata('processing:extension', extension)) if isinstance(param, DESTINATION_VECTOR_LAYER_TYPES): kwargs['metadata'].append( Metadata('processing:dataType', str(param.dataType()))) return LiteralInput(**kwargs) else: return None
def get_processing_value(param: QgsProcessingParameterDefinition, inp: WPSInput, context: ProcessingContext) -> Any: """ Return processing values from WPS input data """ if isinstance(param, DESTINATION_LAYER_TYPES): # # Destination layer: a new layer is created as file with the input name. # Do not supports memory layer because we need persistence # param.setSupportsNonFileBasedOutput(False) # # Enforce pushing created layers to layersToLoadOnCompletion list # i.e layer will be stored in the destination project # get extension from input metadata (should always exist for destination) extension = get_metadata(inp[0], 'processing:extension')[0] destination = inp[0].data if confservice.getboolean('processing', 'unsafe.raw_destination_input_sink'): sink, destination = parse_root_destination_path( param, destination, extension) else: # Use canonical file name sink = "./%s.%s" % (get_valid_filename(param.name()), extension) value = QgsProcessingOutputLayerDefinition(sink, context.destination_project) value.destinationName = destination LOGGER.debug("Handling destination layer: %s, details name: %s", param.name(), value.destinationName) elif isinstance(param, QgsProcessingParameterFeatureSource): # # Support feature selection # value, has_selection = parse_layer_spec(inp[0].data, context, allow_selection=True) value = QgsProcessingFeatureSourceDefinition( value, selectedFeaturesOnly=has_selection) elif isinstance(param, INPUT_LAYER_TYPES): if len(inp) > 1: value = [parse_layer_spec(i.data, context)[0] for i in inp] else: value, _ = parse_layer_spec(inp[0].data, context) else: value = None return value
def __init__(self, name='', description='', options=[], default=None, isSource=False, multiple=False, optional=False): QgsProcessingParameterDefinition.__init__(self, name, description, default, optional) self.setMetadata({'widget_wrapper': {'class': LittoDynValueWrapper}})
def __init__( self, name="", description="", options=[], default=None, isSource=False, multiple=False, optional=False, ): QgsProcessingParameterDefinition.__init__( self, name, description, default, optional ) self.setMetadata({"widget_wrapper": {"class": LittoDynRasterComboBoxWrapper}})
def __init__(self, name='', description='', options=[], default=None, isSource=False, multiple=False, optional=False): QgsProcessingParameterDefinition.__init__(self, name, description, default, optional) self.setMetadata({ 'widget_wrapper': { 'class': 'processing.algs.otb.OtbChoiceWidget.OtbChoiceWidgetWrapper'}}) self.options = options if default is not None: try: self.default = int(default) except: self.default = 0 self.value = self.default
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 parse_extent_input( param: QgsProcessingParameterDefinition, kwargs ) -> BoundingBoxInput: """ Convert extent processing input to bounding box input" """ typ = param.type() if typ == "extent": # XXX This is the default, do not presume anything # about effective crs at compute time kwargs['crss'] = ['EPSG:4326'] return BoundingBoxInput(**kwargs)
def get_processing_value(param: QgsProcessingParameterDefinition, inp: LiteralInput, context: ProcessingContext) -> Any: """ Return processing value from wps inputs Processes other inputs than layers """ typ = param.type() if typ != 'datetime': return None value = inp[0].data # Convert python datetime to appropriate object dtype = param.dataType() if dtype == QgsProcessingParameterDateTime.Date: value = QDate(value) elif dtype == QgsProcessingParameterDateTime.Time: value = QTime(value) else: value = QDateTime(value) return value
def get_layers_type(param: QgsProcessingParameterDefinition, kwargs) -> None: """ Set datatype as metadata """ datatypes = [] if isinstance(param, QgsProcessingParameterLimitedDataTypes): datatypes = param.dataTypes() if not datatypes: if isinstance(param, INPUT_VECTOR_LAYER_TYPES): datatypes = [QgsProcessing.TypeVector] elif isinstance(param, INPUT_RASTER_LAYER_TYPES): datatypes = [QgsProcessing.TypeRaster] elif isinstance(param, QgsProcessingParameterMultipleLayers): datatypes = [param.layerType()] elif isinstance(param, QgsProcessingParameterMeshLayer): datatypes = [QgsProcessing.TypeMesh] else: datatypes = [QgsProcessing.TypeMapLayer] kwargs['metadata'].append( Metadata('processing:dataTypes', ','.join(SourceTypes[dtyp] for dtyp in datatypes))) return datatypes
def get_processing_value(param: QgsProcessingParameterDefinition, inp: WPSInput, context: ProcessingContext) -> Any: """ Return processing value from wps inputs Processes other inputs than layers """ typ = param.type() if typ == 'enum': # XXX Processing wants the index of the value in option list if param.allowMultiple() and len(inp) > 1: opts = param.options() value = [opts.index(d.data) for d in inp] else: value = param.options().index(inp[0].data) elif len(inp): # Return raw value value = inp[0].data else: # Return undefined value if not _is_optional(param): LOGGER.warning("Required input %s has no value", param.name()) value = None return value
def parse_input_definition(param: QgsProcessingParameterDefinition, alg: QgsProcessingAlgorithm = None, context: MapContext = None) -> WPSInput: """ Create WPS input from QgsProcessingParamDefinition the description is used in QGIS UI as the title in WPS. see https://qgis.org/api/qgsprocessingparameters_8h_source.html#l01312 """ kwargs = { 'identifier': param.name(), 'title': param.description() or param.name().replace('_', ' '), 'abstract': param.help(), 'metadata': [ Metadata('processing:type', param.type()), ] } # Handle defaultValue # XXX In some case QVariant are # not converted to python object (SIP bug ?) # Problem stated in getting QgsProcessingParameterFeatureSource # from processing.core.parameters.getParameterFromString defaultValue = param.defaultValue() if isinstance(defaultValue, QVariant): defaultValue = None if defaultValue.isNull() else defaultValue.value() kwargs['default'] = defaultValue # Check for optional flags if _is_optional(param): kwargs['min_occurs'] = 0 inp = parse_literal_input(param,kwargs) \ or layersio.parse_input_definition(param, kwargs, context) \ or geometryio.parse_input_definition(param, kwargs, context) \ or filesio.parse_input_definition(param, kwargs) \ or datetimeio.parse_input_definition(param, kwargs) if inp is None: raise ProcessingInputTypeNotSupported("%s:'%s'" % (type(param), param.type())) parse_metadata(param, kwargs) return inp
def get_processing_value(param: QgsProcessingParameterDefinition, inp: WPSInput, context: ProcessingContext) -> Any: """ Return processing value from wps inputs Processes other inputs than layers """ typ = param.type() if isinstance(param, QgsProcessingParameterGeometry): value = input_to_geometry(inp[0]) elif isinstance(param, QgsProcessingParameterPoint): value = input_to_point(inp[0]) elif typ == 'extent': value = input_to_extent(inp[0]) elif typ == 'crs': # XXX CRS may be expressed as EPSG (or QgsProperty ?) value == inp[0].data else: value = None return value
def parse_input_definition(param: QgsProcessingParameterDefinition, kwargs) -> LiteralInput: """ Convert processing input to File Input """ typ = param.type() if typ != 'datetime': return None def to_value(qdt): return qdt.toPyDateTime() if qdt.isValid() else None defval = kwargs['default'] dtype = param.dataType() if dtype == QgsProcessingParameterDateTime.Date: kwargs['data_type'] = 'date' maxval = (to_value(param.maximum()) or datetime.max).date() minval = (to_value(param.minimum()) or datetime.min).date() if defval: defval = QDateTime(defval).toPyDateTime().date() elif dtype == QgsProcessingParameterDateTime.Time: kwargs['data_type'] = 'time' maxval = (to_value(param.maximum()) or datetime.max).time() minval = (to_value(param.minimum()) or datetime.min).time() if defval: defval = convert_time(defval.toString(Qt.ISODate)) else: kwargs['data_type'] = 'dateTime' maxval = to_value(param.maximum()) or datetime.max minval = to_value(param.minimum()) or datetime.min if defval: defval = defval.toPyDateTime() kwargs['default'] = defval return LiteralInput(allowed_values=[(minval, maxval)], **kwargs)
def _is_hidden(param: QgsProcessingParameterDefinition) -> bool: return (int(param.flags()) & QgsProcessingParameterDefinition.FlagHidden) != 0
def parse_metadata(param: QgsProcessingParameterDefinition, kwargs) -> None: """ Parse freeform metadata """ kwargs['metadata'].extend( Metadata('processing:meta:%s' % k, str(v)) for k, v in param.metadata().items())
def _is_optional(param: QgsProcessingParameterDefinition) -> bool: return (int(param.flags()) & QgsProcessingParameterDefinition.FlagOptional) != 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)