def runAndLoadResults(algOrName, parameters, feedback=None, context=None): """ Executes given algorithm and load its results into the current QGIS project when possible. :param algOrName: Either an instance of an algorithm, or an algorithm's ID :param parameters: Algorithm parameters dictionary :param feedback: Processing feedback object :param context: Processing context object :returns algorithm results as a dictionary, or None if execution failed :rtype: Union[dict, None] """ if isinstance(algOrName, QgsProcessingAlgorithm): alg = algOrName else: alg = QgsApplication.processingRegistry().createAlgorithmById(algOrName) # output destination parameters to point to current project for param in alg.parameterDefinitions(): if not param.name() in parameters: continue if isinstance(param, (QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination, QgsProcessingParameterRasterDestination)): p = parameters[param.name()] if not isinstance(p, QgsProcessingOutputLayerDefinition): parameters[param.name()] = QgsProcessingOutputLayerDefinition(p, QgsProject.instance()) else: p.destinationProject = QgsProject.instance() parameters[param.name()] = p return Processing.runAlgorithm(alg, parameters=parameters, onFinish=handleAlgorithmResults, feedback=feedback, context=context)
def runAndLoadResults(algOrName, parameters, feedback=None, context=None): """Executes given algorithm and load its results into QGIS project when possible. """ if isinstance(algOrName, QgsProcessingAlgorithm): alg = algOrName else: alg = QgsApplication.processingRegistry().createAlgorithmById( algOrName) # output destination parameters to point to current project for param in alg.parameterDefinitions(): if not param.name() in parameters: continue if isinstance(param, (QgsProcessingParameterFeatureSink, QgsProcessingParameterVectorDestination, QgsProcessingParameterRasterDestination)): p = parameters[param.name()] if not isinstance(p, QgsProcessingOutputLayerDefinition): parameters[param.name()] = QgsProcessingOutputLayerDefinition( p, QgsProject.instance()) else: p.destinationProject = QgsProject.instance() parameters[param.name()] = p return Processing.runAlgorithm(alg, parameters=parameters, onFinish=handleAlgorithmResults, feedback=feedback, context=context)
def getParamValues(self): if self.mUpdateExistingGroupBox.isChecked(): fieldName = self.mExistingFieldComboBox.currentText() else: fieldName = self.mOutputFieldNameLineEdit.text() layer = self.cmbInputLayer.currentLayer() context = dataobjects.createContext() parameters = {} parameters['INPUT'] = layer parameters['FIELD_NAME'] = fieldName parameters['FIELD_TYPE'] = self.mOutputFieldTypeComboBox.currentIndex() parameters['FIELD_LENGTH'] = self.mOutputFieldWidthSpinBox.value() parameters[ 'FIELD_PRECISION'] = self.mOutputFieldPrecisionSpinBox.value() parameters['NEW_FIELD'] = self.mNewFieldGroupBox.isChecked() parameters['FORMULA'] = self.builder.expressionText() output = QgsProcessingOutputLayerDefinition() if self.leOutputFile.text().strip(): output.sink = QgsProperty.fromValue( self.leOutputFile.text().strip()) else: output.sink = QgsProperty.fromValue('memory:') output.destinationProject = context.project() parameters['OUTPUT'] = output ok, msg = self.alg.checkParameterValues(parameters, context) if not ok: QMessageBox.warning(self, self.tr('Unable to execute algorithm'), msg) return {} return parameters
def getValue(self): key = None if self.use_temporary and isinstance( self.parameter, QgsProcessingParameterFeatureSink): key = 'memory:' elif self.use_temporary and not self.default_selection: key = self.parameter.generateTemporaryDestination() else: key = self.leText.text() if not key and self.parameter.flags( ) & QgsProcessingParameterDefinition.FlagOptional: return None if key and not key.startswith('memory:') \ and not key.startswith('ogr:') \ and not key.startswith('postgres:') \ and not key.startswith('postgis:'): # output should be a file path folder = QFileInfo(key).path() if folder == '.': # output name does not include a folder - use default default_folder = ProcessingConfig.getSetting( ProcessingConfig.OUTPUT_FOLDER) key = QDir(default_folder).filePath(key) if isinstance(self.parameter, QgsProcessingParameterFolderDestination): return key if isinstance(self.parameter, QgsProcessingParameterFileDestination): return key value = QgsProcessingOutputLayerDefinition(key) value.createOptions = {'fileEncoding': self.encoding} return value
def getConsoleCommands(self, parameters, context, feedback): arguments = [] arguments.append('-resolution') arguments.append(self.RESOLUTION_OPTIONS[self.parameterAsEnum(parameters, self.RESOLUTION, context)]) if self.parameterAsBool(parameters, buildvrt.SEPARATE, context): arguments.append('-separate') if self.parameterAsBool(parameters, buildvrt.PROJ_DIFFERENCE, context): arguments.append('-allow_projection_difference') # Always write input files to a text file in case there are many of them and the # length of the command will be longer then allowed in command prompt listFile = os.path.join(QgsProcessingUtils.tempFolder(), 'buildvrtInputFiles.txt') with open(listFile, 'w') as f: layers = [] for l in self.parameterAsLayerList(parameters, self.INPUT, context): layers.append(l.source()) f.write('\n'.join(layers)) arguments.append('-input_file_list') arguments.append(listFile) out = self.parameterAsOutputLayer(parameters, self.OUTPUT, context) # Ideally the file extensions should be limited to just .vrt but I'm not sure how # to do it simply so instead a check is performed. _, ext = os.path.splitext(out) if not ext.lower() == '.vrt': out = out[:-len(ext)] + '.vrt' if isinstance(parameters[self.OUTPUT], QgsProcessingOutputLayerDefinition): output_def = QgsProcessingOutputLayerDefinition(parameters[self.OUTPUT]) output_def.sink = QgsProperty.fromValue(out) self.setOutputValue(self.OUTPUT, output_def) else: self.setOutputValue(self.OUTPUT, out) arguments.append(out) return ['gdalbuildvrt', GdalUtils.escapeAndJoin(arguments)]
def getValue(self): key = None if not self.leText.text(): if isinstance(self.parameter, QgsProcessingParameterFeatureSink): key = 'memory:' else: key = self.leText.text() value = QgsProcessingOutputLayerDefinition(key) value.createOptions = {'fileEncoding': self.encoding} return value
def parametersForRow(self, row, destinationProject=None, warnOnInvalid=True): """ Returns the parameters dictionary corresponding to a row in the batch table """ col = 0 parameters = {} for param in self.alg.parameterDefinitions(): if param.flags( ) & QgsProcessingParameterDefinition.FlagHidden or param.isDestination( ): continue wrapper = self.wrappers[row][col] parameters[param.name()] = wrapper.parameterValue() if warnOnInvalid and not param.checkValueIsAcceptable( wrapper.parameterValue()): self.parent.messageBar().pushMessage( "", self.tr('Wrong or missing parameter value: {0} (row {1})' ).format(param.description(), row + 1), level=Qgis.Warning, duration=5) return {} col += 1 count_visible_outputs = 0 for out in self.alg.destinationParameterDefinitions(): if out.flags() & QgsProcessingParameterDefinition.FlagHidden: continue count_visible_outputs += 1 widget = self.tblParameters.cellWidget(row + 1, col) text = widget.getValue() if not warnOnInvalid or out.checkValueIsAcceptable(text): if isinstance(out, (QgsProcessingParameterRasterDestination, QgsProcessingParameterVectorDestination, QgsProcessingParameterFeatureSink)): # load rasters and sinks on completion parameters[ out.name()] = QgsProcessingOutputLayerDefinition( text, destinationProject) else: parameters[out.name()] = text col += 1 else: self.parent.messageBar().pushMessage( "", self.tr( 'Wrong or missing output value: {0} (row {1})').format( out.description(), row + 1), level=Qgis.Warning, duration=5) return {} return parameters
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 test_layer_destination(): param = QgsProcessingParameterVectorDestination( "LAYER", "", defaultValue=QgsProcessingOutputLayerDefinition('foo.shp')) inp = parse_input_definition(param) assert inp.default == "foo" metadata = layersio.get_metadata(inp, 'processing:extension') assert len(metadata) == 1 assert metadata[0] == 'shp' inp.data = "bar" context = QgsProcessingContext() context.destination_project = None inp.data = "bar" value = layersio.get_processing_value(param, [inp], context) assert isinstance(value, QgsProcessingOutputLayerDefinition) assert value.destinationName == 'bar' assert value.sink.staticValue() == './LAYER.shp' # Check unsafe option with chconfig('processing', 'unsafe.raw_destination_input_sink', 'yes'): inp.data = "/foobar.csv" value = layersio.get_processing_value(param, [inp], context) assert value.destinationName == 'foobar' assert value.sink.staticValue() == 'foobar.csv' # Check unsafe option with default extension with chconfig('processing', 'unsafe.raw_destination_input_sink', 'yes'): inp.data = "/foobar" value = layersio.get_processing_value(param, [inp], context) assert value.destinationName == 'foobar' assert value.sink.staticValue() == 'foobar.shp' # Check unsafe option with layername with chconfig('processing','unsafe.raw_destination_input_sink','yes'),\ chconfig('processing','destination_root_path','/unsafe'): inp.data = "file:/path/to/foobar.csv|layername=foobaz" value = layersio.get_processing_value(param, [inp], context) assert value.destinationName == 'foobaz' assert value.sink.staticValue() == '/unsafe/path/to/foobar.csv' # Check unsafe option with url with chconfig('processing', 'unsafe.raw_destination_input_sink', 'yes'): inp.data = "postgres://service=foobar|layername=foobaz" value = layersio.get_processing_value(param, [inp], context) assert value.destinationName == 'foobaz' assert value.sink.staticValue() == 'postgres://service=foobar'
def initAlgorithm(self, config=None): """ Virtual override see https://qgis.org/api/classQgsProcessingAlgorithm.html """ self.addParameter( QgsProcessingParameterVectorLayer(self.INPUT, 'Vector Layer')) self.addParameter( QgsProcessingParameterVectorDestination( self.OUTPUT, 'Output Layer', defaultValue=QgsProcessingOutputLayerDefinition( f'{self.OUTPUT}.shp')))
def test_output_layer_definition(self): """ Test that QgsProcessingOutputLayerDefinition values are correctly loaded and written """ doc = QDomDocument("properties") definition = QgsProcessingOutputLayerDefinition(QgsProperty.fromValue('my sink')) definition.createOptions = {'opt': 1, 'opt2': 2} elem = QgsXmlUtils.writeVariant(definition, doc) c = QgsXmlUtils.readVariant(elem) self.assertEqual(c.sink.staticValue(), 'my sink') self.assertEqual(c.createOptions, {'opt': 1, 'opt2': 2})
def getValue(self): key = None if self.use_temporary and isinstance( self.parameter, QgsProcessingParameterFeatureSink): key = 'memory:' else: key = self.leText.text() if not key and self.parameter.flags( ) & QgsProcessingParameterDefinition.FlagOptional: return None value = QgsProcessingOutputLayerDefinition(key) value.createOptions = {'fileEncoding': self.encoding} return value
def getValue(self): key = None if self.use_temporary and isinstance(self.parameter, QgsProcessingParameterFeatureSink): key = 'memory:' elif self.use_temporary and not self.default_selection: key = self.parameter.generateTemporaryDestination() else: key = self.leText.text() if not key and self.parameter.flags() & QgsProcessingParameterDefinition.FlagOptional: return None if isinstance(self.parameter, QgsProcessingParameterFolderDestination): return key if isinstance(self.parameter, QgsProcessingParameterFileDestination): return key value = QgsProcessingOutputLayerDefinition(key) value.createOptions = {'fileEncoding': self.encoding} return value
def __init__( self, algorithm_id: str, artifact_parameter_name: str, output_name: str, negate_output: bool, artifact_path: typing.Union[str, Path], model: QtCore.QAbstractItemModel, validated_idx: QtCore.QModelIndex, notes_idx: QtCore.QModelIndex, execution_params: typing.Optional[typing.Dict] = None, context: typing.Optional[QgsProcessingContext] = None, feedback: typing.Optional[QgsProcessingFeedback] = None, ): self.context = context or QgsProcessingContext() self.feedback = feedback or QgsProcessingFeedback() registry = QgsApplication.processingRegistry() algorithm = registry.createAlgorithmById(algorithm_id) if algorithm is None: raise RuntimeError(f"Invalid algorithm_id: {algorithm_id!r}") self.algorithm = algorithm self.output_name = output_name self.negate_output = negate_output self.model = model self.validated_idx = validated_idx self.notes_idx = notes_idx self.params = dict(execution_params) if execution_params else {} if isinstance(artifact_path, Path): input_ = str(artifact_path) else: input_ = artifact_path self.params.update({artifact_parameter_name: input_}) for param_def in self.algorithm.parameterDefinitions(): if isinstance(param_def, self._OUTPUT_TYPES): out_layer_definition = QgsProcessingOutputLayerDefinition( "memory:") out_layer_definition.createOptions = {"fileEncoding": "utf-8"} self.params[param_def.name()] = out_layer_definition
def processAlgorithm(self, parameters, context, model_feedback): feedback = QgsProcessingMultiStepFeedback(4, model_feedback) results = {} outputs = {} sections = self.parameterAsSource(parameters, self.SECTIONS, context) # Retreive first section longitudinal abscissa request = (QgsFeatureRequest().setFlags( QgsFeatureRequest.NoGeometry | QgsFeatureRequest.SubsetOfAttributes).setSubsetOfAttributes( ["abs_long"], sections.fields()).addOrderBy('"sec_id"', True, True).setLimit(1)) first_section = next(sections.getFeatures(request)) first_abs_long = first_section.attribute("abs_long") # Lines to points alg_params = { "INPUT": parameters[self.SECTIONS], "OUTPUT": QgsProcessingUtils.generateTempFilename("lines_to_points.shp"), } outputs["LinesToPoints"] = processing.run( "precourlis:lines_to_points", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) current = outputs["LinesToPoints"]["OUTPUT"] feedback.setCurrentStep(1) if feedback.isCanceled(): return {} # Interpolate points alg_params = { "SECTIONS": current, "AXIS": parameters[self.AXIS], "CONSTRAINT_LINES": parameters.get(self.CONSTRAINT_LINES), "LONG_STEP": parameters[self.LONG_STEP], "LAT_STEP": parameters[self.LAT_STEP], "ATTR_CROSS_SECTION": "sec_id", "OUTPUT": QgsProcessingUtils.generateTempFilename("interpolate_points.shp"), } outputs["InterpolatePoints"] = processing.run( "precourlis:interpolate_points", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) current = outputs["InterpolatePoints"]["OUTPUT"] feedback.setCurrentStep(2) if feedback.isCanceled(): return {} # assignprojection alg_params = { "INPUT": current, "CRS": sections.sourceCrs(), "OUTPUT": QgsProcessing.TEMPORARY_OUTPUT, } outputs["AssignProjection"] = processing.run( "native:assignprojection", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) current = outputs["AssignProjection"]["OUTPUT"] feedback.setCurrentStep(3) if feedback.isCanceled(): return {} output = QgsProcessingOutputLayerDefinition(parameters[self.OUTPUT]) output.destinationName = self.tr("Interpolated") # Points to lines alg_params = { "INPUT": current, "AXIS": parameters[self.AXIS], "FIRST_SECTION_ABS_LONG": first_abs_long, "GROUP_FIELD": "abs_long", "ORDER_FIELD": "p_id", "OUTPUT": output, } outputs["PointsToLines"] = processing.run( "precourlis:points_to_lines", alg_params, context=context, feedback=feedback, is_child_algorithm=True, ) current = outputs["PointsToLines"]["OUTPUT"] results["OUTPUT"] = current return results
def accept(self): alg_parameters = [] load = [] feedback = self.createFeedback() context = dataobjects.createContext(feedback) for row in range(self.mainWidget.tblParameters.rowCount()): col = 0 parameters = {} for param in self.alg.parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagHidden or param.isDestination(): continue wrapper = self.mainWidget.wrappers[row][col] parameters[param.name()] = wrapper.value() if not param.checkValueIsAcceptable(wrapper.value(), context): self.bar.pushMessage("", self.tr('Wrong or missing parameter value: {0} (row {1})').format( param.description(), row + 1), level=QgsMessageBar.WARNING, duration=5) return col += 1 count_visible_outputs = 0 for out in self.alg.destinationParameterDefinitions(): if out.flags() & QgsProcessingParameterDefinition.FlagHidden: continue count_visible_outputs += 1 widget = self.mainWidget.tblParameters.cellWidget(row, col) text = widget.getValue() if param.checkValueIsAcceptable(text, context): if isinstance(out, (QgsProcessingParameterRasterDestination, QgsProcessingParameterFeatureSink)): # load rasters and sinks on completion parameters[out.name()] = QgsProcessingOutputLayerDefinition(text, context.project()) else: parameters[out.name()] = text col += 1 else: self.bar.pushMessage("", self.tr('Wrong or missing output value: {0} (row {1})').format( out.description(), row + 1), level=QgsMessageBar.WARNING, duration=5) return alg_parameters.append(parameters) QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) self.mainWidget.setEnabled(False) self.buttonCancel.setEnabled(True) # Make sure the Log tab is visible before executing the algorithm try: self.tabWidget.setCurrentIndex(1) self.repaint() except: pass start_time = time.time() algorithm_results = [] for count, parameters in enumerate(alg_parameters): if feedback.isCanceled(): break self.setText(self.tr('\nProcessing algorithm {0}/{1}...').format(count + 1, len(alg_parameters))) self.setInfo(self.tr('<b>Algorithm {0} starting...</b>').format(self.alg.displayName()), escape_html=False) feedback.pushInfo(self.tr('Input parameters:')) feedback.pushCommandInfo(pformat(parameters)) feedback.pushInfo('') alg_start_time = time.time() ret, results = execute(self.alg, parameters, context, feedback) if ret: self.setInfo(self.tr('Algorithm {0} correctly executed...').format(self.alg.displayName()), escape_html=False) feedback.setProgress(100) feedback.pushInfo( self.tr('Execution completed in {0:0.2f} seconds'.format(time.time() - alg_start_time))) feedback.pushInfo(self.tr('Results:')) feedback.pushCommandInfo(pformat(results)) feedback.pushInfo('') algorithm_results.append(results) else: break feedback.pushInfo(self.tr('Batch execution completed in {0:0.2f} seconds'.format(time.time() - start_time))) handleAlgorithmResults(self.alg, context, feedback, False) self.finish(algorithm_results) self.buttonCancel.setEnabled(False)
def accept(self): alg_parameters = [] feedback = self.createFeedback() load_layers = self.mainWidget().checkLoadLayersOnCompletion.isChecked() project = QgsProject.instance() if load_layers else None for row in range(self.mainWidget().tblParameters.rowCount()): col = 0 parameters = {} for param in self.algorithm().parameterDefinitions(): if param.flags() & QgsProcessingParameterDefinition.FlagHidden or param.isDestination(): continue wrapper = self.mainWidget().wrappers[row][col] parameters[param.name()] = wrapper.value() if not param.checkValueIsAcceptable(wrapper.value()): self.messageBar().pushMessage("", self.tr('Wrong or missing parameter value: {0} (row {1})').format( param.description(), row + 1), level=Qgis.Warning, duration=5) return col += 1 count_visible_outputs = 0 for out in self.algorithm().destinationParameterDefinitions(): if out.flags() & QgsProcessingParameterDefinition.FlagHidden: continue count_visible_outputs += 1 widget = self.mainWidget().tblParameters.cellWidget(row, col) text = widget.getValue() if out.checkValueIsAcceptable(text): if isinstance(out, (QgsProcessingParameterRasterDestination, QgsProcessingParameterFeatureSink)): # load rasters and sinks on completion parameters[out.name()] = QgsProcessingOutputLayerDefinition(text, project) else: parameters[out.name()] = text col += 1 else: self.messageBar().pushMessage("", self.tr('Wrong or missing output value: {0} (row {1})').format( out.description(), row + 1), level=Qgis.Warning, duration=5) return alg_parameters.append(parameters) with OverrideCursor(Qt.WaitCursor): self.mainWidget().setEnabled(False) self.cancelButton().setEnabled(True) # Make sure the Log tab is visible before executing the algorithm try: self.showLog() self.repaint() except: pass start_time = time.time() algorithm_results = [] for count, parameters in enumerate(alg_parameters): if feedback.isCanceled(): break self.setProgressText(QCoreApplication.translate('BatchAlgorithmDialog', '\nProcessing algorithm {0}/{1}…').format(count + 1, len(alg_parameters))) self.setInfo(self.tr('<b>Algorithm {0} starting…</b>').format(self.algorithm().displayName()), escapeHtml=False) feedback.pushInfo(self.tr('Input parameters:')) feedback.pushCommandInfo(pformat(parameters)) feedback.pushInfo('') # important - we create a new context for each iteration # this avoids holding onto resources and layers from earlier iterations, # and allows batch processing of many more items then is possible # if we hold on to these layers context = dataobjects.createContext(feedback) alg_start_time = time.time() ret, results = execute(self.algorithm(), parameters, context, feedback) if ret: self.setInfo(QCoreApplication.translate('BatchAlgorithmDialog', 'Algorithm {0} correctly executed…').format(self.algorithm().displayName()), escapeHtml=False) feedback.setProgress(100) feedback.pushInfo( self.tr('Execution completed in {0:0.2f} seconds'.format(time.time() - alg_start_time))) feedback.pushInfo(self.tr('Results:')) feedback.pushCommandInfo(pformat(results)) feedback.pushInfo('') algorithm_results.append(results) else: break handleAlgorithmResults(self.algorithm(), context, feedback, False) feedback.pushInfo(self.tr('Batch execution completed in {0:0.2f} seconds'.format(time.time() - start_time))) self.finish(algorithm_results) self.cancelButton().setEnabled(False)
def input_to_processing(identifier: str, inp: WPSInput, alg: QgsProcessingAlgorithm, context: ProcessingContext) -> Tuple[str, Any]: """ Convert wps input to processing param see https://qgis.org/api/classQgsProcessingOutputLayerDefinition.html see https://qgis.org/api/qgsprocessingparameters_8cpp_source.html#L272 see ./python/plugins/processing/tools/general.py:111 see ./python/plugins/processing/gui/Postprocessing.py:50 see ./python/plugins/processing/core/Processing.py:126 """ param = alg.parameterDefinition(identifier) typ = param.type() if isinstance(param, DESTINATION_LAYER_TYPES): # Do not supports memory: layer since we are storing destination project to file param.setSupportsNonFileBasedOutput(False) # Enforce pushing created layers to layersToLoadOnCompletion list sink = "./%s.%s" % (param.name(), param.defaultFileExtension()) value = QgsProcessingOutputLayerDefinition(sink, context.destination_project) value.destinationName = inp[0].data 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) elif 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 typ == 'extent': value = input_to_extent(inp) elif typ == 'crs': # XXX CRS may be expressed as EPSG (or QgsProperty ?) value = inp[0].data elif 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'", identifier, inp[0].data, value) 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", identifier) value = None return param.name(), value