Esempio n. 1
0
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)
Esempio n. 2
0
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
Esempio n. 3
0
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)
Esempio n. 4
0
    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
Esempio n. 5
0
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
Esempio n. 6
0
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'])
Esempio n. 7
0
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
Esempio n. 8
0
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
Esempio n. 9
0
    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}})
Esempio n. 10
0
    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}})
Esempio n. 11
0
    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
Esempio n. 12
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. 13
0
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)
Esempio n. 14
0
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
Esempio n. 15
0
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
Esempio n. 16
0
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
Esempio n. 17
0
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
Esempio n. 18
0
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
Esempio n. 19
0
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)
Esempio n. 20
0
def _is_hidden(param: QgsProcessingParameterDefinition) -> bool:
    return (int(param.flags())
            & QgsProcessingParameterDefinition.FlagHidden) != 0
Esempio n. 21
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())
Esempio n. 22
0
def _is_optional(param: QgsProcessingParameterDefinition) -> bool:
    return (int(param.flags())
            & QgsProcessingParameterDefinition.FlagOptional) != 0
Esempio n. 23
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)