Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[processing] More helpful errors when sources cannot be loaded
Include descriptive text with the specified parameter value
in error, and always check that sources were loaded to avoid
raw Python exceptions when they are not
  • Loading branch information
nyalldawson committed Apr 27, 2018
1 parent 199af26 commit 5339d62
Show file tree
Hide file tree
Showing 95 changed files with 469 additions and 43 deletions.
26 changes: 26 additions & 0 deletions python/core/processing/qgsprocessingalgorithm.sip.in
Expand Up @@ -744,6 +744,32 @@ Evaluates the parameter with matching ``name`` to a range of values.
QStringList parameterAsFields( const QVariantMap &parameters, const QString &name, QgsProcessingContext &context ) const;
%Docstring
Evaluates the parameter with matching ``name`` to a list of fields.
%End

static QString invalidSourceError( const QVariantMap &parameters, const QString &name );
%Docstring
Returns a user-friendly string to use as an error when a source parameter could
not be loaded.

The ``parameters`` argument should give the algorithms parameter map, and the ``name``
should correspond to the invalid source parameter name.

.. versionadded:: 3.2

.. seealso:: :py:func:`invalidSinkError`
%End

static QString invalidSinkError( const QVariantMap &parameters, const QString &name );
%Docstring
Returns a user-friendly string to use as an error when a sink parameter could
not be created.

The ``parameters`` argument should give the algorithms parameter map, and the ``name``
should correspond to the invalid source parameter name.

.. versionadded:: 3.2

.. seealso:: :py:func:`invalidSourceError`
%End

private:
Expand Down
6 changes: 5 additions & 1 deletion python/plugins/processing/algs/gdal/Buffer.py
Expand Up @@ -32,6 +32,7 @@
QgsProcessingParameterField,
QgsProcessingParameterString,
QgsProcessingParameterNumber,
QgsProcessingException,
QgsProcessingParameterBoolean,
QgsProcessingParameterVectorDestination)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
Expand Down Expand Up @@ -103,7 +104,10 @@ def commandName(self):
return 'ogr2ogr'

def getConsoleCommands(self, parameters, context, feedback, executing=True):
fields = self.parameterAsSource(parameters, self.INPUT, context).fields()
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))
fields = source.fields()
ogrLayer, layerName = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
geometry = self.parameterAsString(parameters, self.GEOMETRY, context)
distance = self.parameterAsDouble(parameters, self.DISTANCE, context)
Expand Down
4 changes: 4 additions & 0 deletions python/plugins/processing/algs/gdal/ClipVectorByExtent.py
Expand Up @@ -27,6 +27,7 @@

from qgis.core import (QgsVectorLayer,
QgsProcessing,
QgsProcessingException,
QgsProcessingParameterDefinition,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterExtent,
Expand Down Expand Up @@ -80,6 +81,9 @@ def commandName(self):
def getConsoleCommands(self, parameters, context, feedback, executing=True):
ogrLayer, layerName = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

extent = self.parameterAsExtent(parameters, self.EXTENT, context, source.sourceCrs())
options = self.parameterAsString(parameters, self.OPTIONS, context)
outFile = self.parameterAsOutputLayer(parameters, self.OUTPUT, context)
Expand Down
7 changes: 6 additions & 1 deletion python/plugins/processing/algs/gdal/Dissolve.py
Expand Up @@ -26,6 +26,7 @@
__revision__ = '$Format:%H$'

from qgis.core import (QgsProcessing,
QgsProcessingException,
QgsProcessingParameterDefinition,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterField,
Expand Down Expand Up @@ -113,7 +114,11 @@ def commandName(self):
return 'ogr2ogr'

def getConsoleCommands(self, parameters, context, feedback, executing=True):
fields = self.parameterAsSource(parameters, self.INPUT, context).fields()
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

fields = source.fields()
ogrLayer, layerName = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
geometry = self.parameterAsString(parameters, self.GEOMETRY, context)
fieldName = self.parameterAsString(parameters, self.FIELD, context)
Expand Down
7 changes: 6 additions & 1 deletion python/plugins/processing/algs/gdal/OffsetCurve.py
Expand Up @@ -30,6 +30,7 @@
QgsProcessingParameterDistance,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterString,
QgsProcessingException,
QgsProcessingParameterNumber,
QgsProcessingParameterVectorDestination)
from processing.algs.gdal.GdalAlgorithm import GdalAlgorithm
Expand Down Expand Up @@ -86,7 +87,11 @@ def commandName(self):
return 'ogr2ogr'

def getConsoleCommands(self, parameters, context, feedback, executing=True):
fields = self.parameterAsSource(parameters, self.INPUT, context).fields()
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

fields = source.fields()
ogrLayer, layerName = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
geometry = self.parameterAsString(parameters, self.GEOMETRY, context)
distance = self.parameterAsDouble(parameters, self.DISTANCE, context)
Expand Down
7 changes: 6 additions & 1 deletion python/plugins/processing/algs/gdal/OneSideBuffer.py
Expand Up @@ -26,6 +26,7 @@
__revision__ = '$Format:%H$'

from qgis.core import (QgsProcessing,
QgsProcessingException,
QgsProcessingParameterDefinition,
QgsProcessingParameterDistance,
QgsProcessingParameterFeatureSource,
Expand Down Expand Up @@ -112,7 +113,11 @@ def commandName(self):
return 'ogr2ogr'

def getConsoleCommands(self, parameters, context, feedback, executing=True):
fields = self.parameterAsSource(parameters, self.INPUT, context).fields()
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

fields = source.fields()
ogrLayer, layerName = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
geometry = self.parameterAsString(parameters, self.GEOMETRY, context)
distance = self.parameterAsDouble(parameters, self.DISTANCE, context)
Expand Down
9 changes: 7 additions & 2 deletions python/plugins/processing/algs/gdal/PointsAlongLines.py
Expand Up @@ -25,7 +25,8 @@

__revision__ = '$Format:%H$'

from qgis.core import (QgsProcessingParameterFeatureSource,
from qgis.core import (QgsProcessingException,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterString,
QgsProcessingParameterNumber,
QgsProcessingParameterVectorDestination,
Expand Down Expand Up @@ -90,7 +91,11 @@ def commandName(self):
return 'ogr2ogr'

def getConsoleCommands(self, parameters, context, feedback, executing=True):
fields = self.parameterAsSource(parameters, self.INPUT, context).fields()
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

fields = source.fields()
ogrLayer, layerName = self.getOgrCompatibleSource(self.INPUT, parameters, context, feedback, executing)
distance = self.parameterAsDouble(parameters, self.DISTANCE, context)
geometry = self.parameterAsString(parameters, self.GEOMETRY, context)
Expand Down
3 changes: 3 additions & 0 deletions python/plugins/processing/algs/qgis/Aggregate.py
Expand Up @@ -131,6 +131,9 @@ def parameterAsAggregates(self, parameters, name, context):

def prepareAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

group_by = self.parameterAsExpression(parameters, self.GROUP_BY, context)
aggregates = self.parameterAsAggregates(parameters, self.AGGREGATES, context)

Expand Down
3 changes: 3 additions & 0 deletions python/plugins/processing/algs/qgis/BarPlot.py
Expand Up @@ -31,6 +31,7 @@

from qgis.core import (QgsProcessingParameterFeatureSource,
QgsProcessingParameterField,
QgsProcessingException,
QgsProcessingParameterFileDestination)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.tools import vector
Expand Down Expand Up @@ -72,6 +73,8 @@ def displayName(self):

def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

namefieldname = self.parameterAsString(parameters, self.NAME_FIELD, context)
valuefieldname = self.parameterAsString(parameters, self.VALUE_FIELD, context)
Expand Down
4 changes: 4 additions & 0 deletions python/plugins/processing/algs/qgis/BasicStatistics.py
Expand Up @@ -35,6 +35,7 @@
QgsStringStatisticalSummary,
QgsDateTimeStatisticalSummary,
QgsFeatureRequest,
QgsProcessingException,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterField,
QgsProcessingParameterFileDestination,
Expand Down Expand Up @@ -128,6 +129,9 @@ def displayName(self):

def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

field_name = self.parameterAsString(parameters, self.FIELD_NAME, context)
field = source.fields().at(source.fields().lookupField(field_name))

Expand Down
6 changes: 5 additions & 1 deletion python/plugins/processing/algs/qgis/BoxPlot.py
Expand Up @@ -28,7 +28,8 @@
import plotly as plt
import plotly.graph_objs as go

from qgis.core import (QgsProcessingParameterFeatureSource,
from qgis.core import (QgsProcessingException,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterField,
QgsProcessingParameterEnum,
QgsProcessingParameterFileDestination,
Expand Down Expand Up @@ -84,6 +85,9 @@ def displayName(self):

def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

namefieldname = self.parameterAsString(parameters, self.NAME_FIELD, context)
valuefieldname = self.parameterAsString(parameters, self.VALUE_FIELD, context)

Expand Down
3 changes: 3 additions & 0 deletions python/plugins/processing/algs/qgis/CheckValidity.py
Expand Up @@ -39,6 +39,7 @@
QgsWkbTypes,
QgsFields,
QgsProcessing,
QgsProcessingException,
QgsProcessingFeatureSource,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterEnum,
Expand Down Expand Up @@ -121,6 +122,8 @@ def processAlgorithm(self, parameters, context, feedback):

def doCheck(self, method, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

(valid_output_sink, valid_output_dest_id) = self.parameterAsSink(parameters, self.VALID_OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())
Expand Down
3 changes: 3 additions & 0 deletions python/plugins/processing/algs/qgis/ConcaveHull.py
Expand Up @@ -79,6 +79,9 @@ def displayName(self):

def processAlgorithm(self, parameters, context, feedback):
layer = self.parameterAsSource(parameters, ConcaveHull.INPUT, context)
if layer is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

alpha = self.parameterAsDouble(parameters, self.ALPHA, context)
holes = self.parameterAsBool(parameters, self.HOLES, context)
no_multigeom = self.parameterAsBool(parameters, self.NO_MULTIGEOMETRY, context)
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/Delaunay.py
Expand Up @@ -79,6 +79,8 @@ def displayName(self):

def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

fields = QgsFields()
fields.append(QgsField('POINTA', QVariant.Double, '', 24, 15))
Expand Down
Expand Up @@ -26,6 +26,7 @@
__revision__ = '$Format:%H$'

from qgis.core import (QgsFeatureRequest,
QgsProcessingException,
QgsFeatureSink,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink)
Expand Down Expand Up @@ -59,6 +60,9 @@ def displayName(self):

def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), source.wkbType(), source.sourceCrs())

Expand Down
4 changes: 4 additions & 0 deletions python/plugins/processing/algs/qgis/ExportGeometryInfo.py
Expand Up @@ -40,6 +40,7 @@
QgsFeatureSink,
QgsDistanceArea,
QgsProcessingUtils,
QgsProcessingException,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterEnum,
QgsProcessingParameterFeatureSink)
Expand Down Expand Up @@ -92,6 +93,9 @@ def displayName(self):

def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

method = self.parameterAsEnum(parameters, self.METHOD, context)

wkb_type = source.wkbType()
Expand Down
Expand Up @@ -77,6 +77,9 @@ def tags(self):

def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

fields = source.fields()
fields.append(QgsField('vertex_pos', QVariant.Int))
fields.append(QgsField('vertex_index', QVariant.Int))
Expand Down
3 changes: 3 additions & 0 deletions python/plugins/processing/algs/qgis/FieldPyculator.py
Expand Up @@ -91,6 +91,9 @@ def displayName(self):

def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

field_name = self.parameterAsString(parameters, self.FIELD_NAME, context)
field_type = self.TYPES[self.parameterAsEnum(parameters, self.FIELD_TYPE, context)]
width = self.parameterAsInt(parameters, self.FIELD_LENGTH, context)
Expand Down
3 changes: 3 additions & 0 deletions python/plugins/processing/algs/qgis/FieldsCalculator.py
Expand Up @@ -94,6 +94,9 @@ def displayName(self):

def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

layer = self.parameterAsVectorLayer(parameters, self.INPUT, context)
field_name = self.parameterAsString(parameters, self.FIELD_NAME, context)
field_type = self.TYPES[self.parameterAsEnum(parameters, self.FIELD_TYPE, context)]
Expand Down
3 changes: 3 additions & 0 deletions python/plugins/processing/algs/qgis/FieldsMapper.py
Expand Up @@ -81,6 +81,9 @@ def parameterAsFieldsMapping(self, parameters, name, context):

def prepareAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, 'INPUT', context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

mapping = self.parameterAsFieldsMapping(parameters, self.FIELDS_MAPPING, context)

self.fields = QgsFields()
Expand Down
3 changes: 3 additions & 0 deletions python/plugins/processing/algs/qgis/FindProjection.py
Expand Up @@ -36,6 +36,7 @@
QgsCoordinateTransform,
QgsCoordinateTransformContext,
QgsWkbTypes,
QgsProcessingException,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterExtent,
QgsProcessingParameterCrs,
Expand Down Expand Up @@ -86,6 +87,8 @@ def displayName(self):

def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

extent = self.parameterAsExtent(parameters, self.TARGET_AREA, context)
target_crs = self.parameterAsCrs(parameters, self.TARGET_AREA_CRS, context)
Expand Down
3 changes: 3 additions & 0 deletions python/plugins/processing/algs/qgis/GeometryConvert.py
Expand Up @@ -77,6 +77,9 @@ def displayName(self):

def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

index = self.parameterAsEnum(parameters, self.TYPE, context)

if index == 0:
Expand Down
2 changes: 2 additions & 0 deletions python/plugins/processing/algs/qgis/Heatmap.py
Expand Up @@ -176,6 +176,8 @@ def clone(self):

def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))

radius = self.parameterAsDouble(parameters, self.RADIUS, context)
kernel_shape = self.parameterAsEnum(parameters, self.KERNEL, context)
Expand Down
6 changes: 6 additions & 0 deletions python/plugins/processing/algs/qgis/HubDistanceLines.py