Skip to content

Commit

Permalink
Port parameter checking to c++
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jun 5, 2017
1 parent a23a6ac commit ef59d0c
Show file tree
Hide file tree
Showing 22 changed files with 1,197 additions and 553 deletions.
11 changes: 11 additions & 0 deletions python/core/processing/qgsprocessingalgorithm.sip
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,17 @@ class QgsProcessingAlgorithm
:rtype: bool
%End

virtual bool checkParameterValues( const QVariantMap &parameters,
QgsProcessingContext &context, QString *message /Out/ = 0 ) const;
%Docstring
Checks the supplied ``parameter`` values to verify that they satisfy the requirements
of this algorithm in the supplied ``context``. The ``message`` parameter will be
filled with explanatory text if validation fails.
Overridden implementations should also check this base class implementation.
:return: true if parameters are acceptable for the algorithm.
:rtype: bool
%End

QgsProcessingProvider *provider() const;
%Docstring
Returns the provider to which this algorithm belongs.
Expand Down
40 changes: 38 additions & 2 deletions python/core/processing/qgsprocessingparameters.sip
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,13 @@ class QgsProcessingParameterDefinition
@see flags()
%End

virtual bool checkValueIsAcceptable( const QVariant &input ) const;
%Docstring
Checks whether the specified ``input`` value is acceptable for the
parameter. Returns true if the value can be accepted.
:rtype: bool
%End

protected:


Expand Down Expand Up @@ -356,7 +363,6 @@ class QgsProcessingParameterBoolean : QgsProcessingParameterDefinition
%End

virtual QString type() const;

};

class QgsProcessingParameterCrs : QgsProcessingParameterDefinition
Expand Down Expand Up @@ -421,7 +427,6 @@ class QgsProcessingParameterExtent : QgsProcessingParameterDefinition

virtual QString type() const;


};


Expand All @@ -444,6 +449,8 @@ class QgsProcessingParameterPoint : QgsProcessingParameterDefinition
%End

virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input ) const;


};

Expand Down Expand Up @@ -472,6 +479,8 @@ class QgsProcessingParameterFile : QgsProcessingParameterDefinition
%End

virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input ) const;


Behavior behavior() const;
%Docstring
Expand Down Expand Up @@ -522,6 +531,8 @@ class QgsProcessingParameterMatrix : QgsProcessingParameterDefinition
%End

virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input ) const;


QStringList headers() const;
%Docstring
Expand Down Expand Up @@ -590,6 +601,8 @@ class QgsProcessingParameterMultipleLayers : QgsProcessingParameterDefinition
%End

virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input ) const;


QgsProcessingParameterDefinition::LayerType layerType() const;
%Docstring
Expand All @@ -602,6 +615,21 @@ class QgsProcessingParameterMultipleLayers : QgsProcessingParameterDefinition
%Docstring
Sets the layer ``type`` for layers acceptable by the parameter.
.. seealso:: layerType()
%End

int minimumNumberInputs() const;
%Docstring
Returns the minimum number of layers required for the parameter. If the return value is < 1
then the parameter accepts any number of layers.
.. seealso:: setMinimumNumberInputs()
:rtype: int
%End

void setMinimumNumberInputs( int minimum );
%Docstring
Sets the ``minimum`` number of layers required for the parameter. The minimum must be >= 1
if the parameter is not optional.
.. seealso:: minimumNumberInputs()
%End

};
Expand Down Expand Up @@ -636,6 +664,8 @@ class QgsProcessingParameterNumber : QgsProcessingParameterDefinition
%End

virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input ) const;


double minimum() const;
%Docstring
Expand Down Expand Up @@ -699,6 +729,8 @@ class QgsProcessingParameterRange : QgsProcessingParameterDefinition
%End

virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input ) const;


QgsProcessingParameterNumber::Type dataType() const;
%Docstring
Expand Down Expand Up @@ -758,6 +790,8 @@ class QgsProcessingParameterEnum : QgsProcessingParameterDefinition
%End

virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input ) const;


QStringList options() const;
%Docstring
Expand Down Expand Up @@ -911,6 +945,8 @@ class QgsProcessingParameterTableField : QgsProcessingParameterDefinition
%End

virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input ) const;


QString parentLayerParameter() const;
%Docstring
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/algs/gdal/GdalAlgorithmDialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,6 @@ def parametersHaveChanged(self):
commands = [c for c in commands if c not in ['cmd.exe', '/C ']]
self.text.setPlainText(" ".join(commands))
except AlgorithmDialogBase.InvalidParameterValue as e:
self.text.setPlainText(self.tr("Invalid value for parameter '{0}'").format(e.parameter.description))
self.text.setPlainText(self.tr("Invalid value for parameter '{0}'").format(e.parameter.description()))
except:
self.text.setPlainText("")
9 changes: 5 additions & 4 deletions python/plugins/processing/algs/grass7/Grass7Algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
from qgis.core import (QgsRasterLayer,
QgsApplication,
QgsProcessingUtils,
QgsMessageLog)
QgsMessageLog,
QgsProcessingAlgorithm)
from qgis.utils import iface

from processing.core.GeoAlgorithm import GeoAlgorithm
Expand Down Expand Up @@ -578,9 +579,9 @@ def canExecute(self):
message = Grass7Utils.checkGrass7IsInstalled()
return not message, message

def checkParameterValuesBeforeExecuting(self):
def checkParameterValues(self, parameters, context):
if self.module:
if hasattr(self.module, 'checkParameterValuesBeforeExecuting'):
func = getattr(self.module, 'checkParameterValuesBeforeExecuting')
return func(self)
return
return func(self), None
return super(Grass7Algorithm, self).checkParameterValues(parameters, context)
4 changes: 2 additions & 2 deletions python/plugins/processing/algs/qgis/FieldPyculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,6 @@ def processAlgorithm(self, parameters, context, feedback):

del writer

def checkParameterValuesBeforeExecuting(self):
def checkParameterValues(self, parameters, context):
# TODO check that formula is correct and fields exist
pass
return super(FieldsPyculator, self).checkParameterValues(parameters, context)
3 changes: 2 additions & 1 deletion python/plugins/processing/algs/qgis/FieldsCalculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,12 @@ def processAlgorithm(self, parameters, context, feedback):
self.tr('An error occurred while evaluating the calculation '
'string:\n{0}').format(error))

def checkParameterValuesBeforeExecuting(self):
def checkParameterValues(self, parameters, context):
newField = self.getParameterValue(self.NEW_FIELD)
fieldName = self.getParameterValue(self.FIELD_NAME).strip()
if newField and len(fieldName) == 0:
return self.tr('Field name is not set. Please enter a field name')
return super(FieldsCalculator, self).checkParameterValues(parameters, context)

def createCustomParametersWidget(self, parent):
return FieldsCalculatorDialog(self)
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,10 @@ def getParamValues(self):
parameters['FORMULA'] = self.builder.expressionText()
parameters['OUTPUT_LAYER'] = self.leOutputFile.text().strip() or None

msg = self.alg.checkParameterValuesBeforeExecuting()
if msg:
context = dataobjects.createContext()

ok, msg = self.alg.checkParameterValues(parameters, context)
if not ok:
QMessageBox.warning(
self, self.tr('Unable to execute algorithm'), msg)
return {}
Expand Down
14 changes: 7 additions & 7 deletions python/plugins/processing/algs/saga/SagaAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,17 +342,16 @@ def exportRasterLayer(self, source):
sessionExportedLayers[source] = destFilename
return 'io_gdal 0 -TRANSFORM 1 -RESAMPLING 0 -GRIDS "' + destFilename + '" -FILES "' + source + '"'

def checkParameterValuesBeforeExecuting(self):
def checkParameterValues(self, parameters, context):
"""
We check that there are no multiband layers, which are not
supported by SAGA, and that raster layers have the same grid extent
"""
extent = None
context = dataobjects.createContext()
for param in self.parameters:
for param in self.parameterDefinitions():
files = []
if isinstance(param, ParameterRaster):
files = [param.value]
files = [parameters[param.name()]]
elif (isinstance(param, ParameterMultipleInput) and
param.datatype == dataobjects.TYPE_RASTER):
if param.value is not None:
Expand All @@ -362,12 +361,13 @@ def checkParameterValuesBeforeExecuting(self):
if layer is None:
continue
if layer.bandCount() > 1:
return self.tr('Input layer {0} has more than one band.\n'
'Multiband layers are not supported by SAGA').format(layer.name())
return False, self.tr('Input layer {0} has more than one band.\n'
'Multiband layers are not supported by SAGA').format(layer.name())
if not self.allowUnmatchingGridExtents:
if extent is None:
extent = (layer.extent(), layer.height(), layer.width())
else:
extent2 = (layer.extent(), layer.height(), layer.width())
if extent != extent2:
return self.tr("Input layers do not have the same grid extent.")
return False, self.tr("Input layers do not have the same grid extent.")
return super(SagaAlgorithm, self).checkParameterValues(parameters, context)
29 changes: 0 additions & 29 deletions python/plugins/processing/core/GeoAlgorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,18 +90,6 @@ def getCustomModelerParametersDialog(self, modelAlg, algName=None):
"""
return None

def checkParameterValuesBeforeExecuting(self):
"""If there is any check to do before launching the execution
of the algorithm, it should be done here.
If values are not correct, a message should be returned
explaining the problem.
This check is called from the parameters dialog, and also when
calling from the console.
"""
return None

def processBeforeAddingToModeler(self, alg, model):
"""Add here any task that has to be performed before adding an algorithm
to a model, such as changing the value of a parameter depending on value
Expand Down Expand Up @@ -150,23 +138,6 @@ def execute(self, parameters, context=None, feedback=None, model=None):
QgsMessageLog.logMessage('\n'.join(lines), self.tr('Processing'), QgsMessageLog.CRITICAL)
raise GeoAlgorithmExecutionException(str(e) + self.tr('\nSee log for more details'), lines, e)

def _checkParameterValuesBeforeExecuting(self, context=None):
if context is None:
context = dataobjects.createContext()
for param in self.parameters:
if isinstance(param, (ParameterRaster, ParameterVector,
ParameterMultipleInput)):
if param.value:
if isinstance(param, ParameterMultipleInput):
inputlayers = param.value.split(';')
else:
inputlayers = [param.value]
for inputlayer in inputlayers:
obj = QgsProcessingUtils.mapLayerFromString(inputlayer, context)
if obj is None:
return "Wrong parameter value: " + param.value
return self.checkParameterValuesBeforeExecuting()

def runPostExecutionScript(self, feedback):
scriptFile = ProcessingConfig.getSetting(
ProcessingConfig.POST_EXECUTION_SCRIPT)
Expand Down
4 changes: 2 additions & 2 deletions python/plugins/processing/core/Processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,8 @@ def runAlgorithm(algOrName, onFinish, *args, **kwargs):
else:
context = dataobjects.createContext()

msg = alg._checkParameterValuesBeforeExecuting(context)
if msg:
ok, msg = alg.checkParameterValues(parameters, context)
if not ok:
# fix_print_with_import
print('Unable to execute algorithm\n' + str(msg))
QgsMessageLog.logMessage(Processing.tr('Unable to execute algorithm\n{0}').format(msg),
Expand Down
21 changes: 5 additions & 16 deletions python/plugins/processing/gui/AlgorithmDialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,18 +101,15 @@ def getParamValues(self):
continue
if not param.isDestination():
wrapper = self.mainWidget.wrappers[param.name()]
value = None
if wrapper.widget:
value = wrapper.value()
parameters[param.name()] = value

#TODO
#if not self.setParamValue(param, wrapper):
# raise AlgorithmDialogBase.InvalidParameterValue(param, wrapper.widget)
if not param.checkValueIsAcceptable(value):
raise AlgorithmDialogBase.InvalidParameterValue(param, wrapper.widget)
else:
parameters[param.name()] = self.mainWidget.outputWidgets[param.name()].getValue()
# TODO
#if isinstance(output, (OutputRaster, OutputVector, OutputTable)):
# output.open = self.mainWidget.checkBoxes[param.name()].isChecked()

return parameters

Expand All @@ -127,12 +124,6 @@ def getLayersToOpen(self):

return layer_outputs

def setParamValue(self, param, wrapper):
if wrapper.widget:
return param.setValue(wrapper.value())
else:
return True

def checkExtentCRS(self):
unmatchingCRS = False
hasExtent = False
Expand Down Expand Up @@ -199,9 +190,7 @@ def accept(self):
QMessageBox.No)
if reply == QMessageBox.No:
return
# TODO
#msg = self.alg._checkParameterValuesBeforeExecuting(context)
msg = None
ok, msg = self.alg.checkParameterValues(parameters, context)
if msg:
QMessageBox.warning(
self, self.tr('Unable to execute algorithm'), msg)
Expand Down Expand Up @@ -258,7 +247,7 @@ def accept(self):
except:
pass
self.bar.clearWidgets()
self.bar.pushMessage("", self.tr("Wrong or missing parameter value: {0}").format(e.parameter.description),
self.bar.pushMessage("", self.tr("Wrong or missing parameter value: {0}").format(e.parameter.description()),
level=QgsMessageBar.WARNING, duration=5)

def finish(self, result, context):
Expand Down
3 changes: 0 additions & 3 deletions python/plugins/processing/gui/AlgorithmDialogBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,6 @@ def setText(self, text):
def getParamValues(self):
return {}

def setParamValue(self, param, widget, alg=None):
pass

def accept(self):
pass

Expand Down
8 changes: 4 additions & 4 deletions python/plugins/processing/gui/BatchAlgorithmDialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ def accept(self):
self.load = []
self.canceled = False

context = dataobjects.createContext()

for row in range(self.mainWidget.tblParameters.rowCount()):
col = 0
parameters = {}
Expand All @@ -81,9 +83,9 @@ def accept(self):
continue
wrapper = self.mainWidget.wrappers[row][col]
parameters[param.name()] = wrapper.value()
if not self.mainWidget.setParamValue(param, wrapper, alg):
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),
param.description(), row + 1),
level=QgsMessageBar.WARNING, duration=5)
self.algs = None
return
Expand Down Expand Up @@ -122,8 +124,6 @@ def accept(self):
except:
pass

context = dataobjects.createContext()

for count, parameters in enumerate(self.alg_parameters):
self.setText(self.tr('\nProcessing algorithm {0}/{1}...').format(count + 1, len(self.alg_parameters)))
self.setInfo(self.tr('<b>Algorithm {0} starting...</b>').format(self.alg.displayName()))
Expand Down
Loading

0 comments on commit ef59d0c

Please sign in to comment.