I'm trying to implement a processing plugins in QGIS 3.28.9, but when I hit Run, it gives me a message that my polygon layer is not a polygon layer, but, it is a polygon, in fact. Can someone help to fix this problem?
code:
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None or source.wkbType() != QgsWkbTypes.PolygonGeometry:
raise QgsProcessingException('Invalid input source. Expected a polygon layer.')
feedback.setProgressText('Converting polygons to lines...')
converted_lines = processing.run("qgis:polygonstolines", {
'INPUT': source,
'OUTPUT': 'memory:' # Convert to a temporary memory layer
})['OUTPUT']
# Get the output sink
sink = self.parameterAsSink(parameters, self.OUTUPUT, context,
converted_lines.fields(), QgsProcessing.TypeVectorLine)
if sink is None:
raise QgsProcessingException('Invalid output sink')
# Add converted lines to the output sink
sink.addFeatures(converted_lines.getFeatures())
return {self.OUTPUT: sink}
1 Answer 1
Your layer has a MultiPolygon
geometry type. Therefore, the source.wkbType()
test will return WkbType.MultiPolygon
which is why the processing exception is being raised.
Change your conditional statement to:
if source is None or QgsWkbTypes.geometryType(source.wkbType()) != QgsWkbTypes.PolygonGeometry:
raise QgsProcessingException('Invalid input source. Expected a polygon layer.')
I assume that you are already passing a list of types to the QgsProcessingParameterFeatureSource
constructor so that the input layer dropdown box is filtered e.g.
def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(
self.INPUT,
self.tr("Input polygon layer"),
[QgsProcessing.TypeVectorPolygon]))
But, since it is still possible to select a different input type when using browse or select file...
...a check of the input geometry type is indeed prudent.
However, I suggest that an alternative (and perhaps better practice) way to run the input check is to re-implement and override the checkParameterValues
method of the QgsProcessingAlgorithm
class and do the check there.
def checkParameterValues(self, parameters, context):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None or QgsWkbTypes.geometryType(source.wkbType()) != QgsWkbTypes.PolygonGeometry:
return False, self.tr('Invalid input source. Expected a polygon layer.')
return super().checkParameterValues(parameters, context)
Here, we can implement our own logic and return False
and a helpful message string if the check fails.
Following this recommendation given in the docs:
Overridden implementations should also check this base class implementation.
we can use super() which returns an object which represents the base or parent class of a subclass (in this case QgsProcessingAlgorithm
) and call the default implementation of checkParameterValues()
, returning the result- as in this example.
Now, if you try to run the algorithm with a non-polygon layer input, you will see this:
Edit: There are a few other issues with your code. You have not passed is_child_algorithm=True
to your processing.run()
call. This is required since the "native:polygonstolines" alg is being run inside a parent algorithm.
As for the persistent error you were getting, I found that to get the child algorithm to accept the parent input, I had to call the materialize()
method on the QgsProcessingFeatureSource
object to return an in memory copy as a QgsVectorLayer
object.
Below is a complete working example. By the way, I guess that you will be adding some more processing steps because, as it is, this whole script is just a wrapper around an existing algorithm. If you add more steps you may want to use QgsProcessingMultiStepFeedback
. You can see an example in my recent answer here.
from qgis.PyQt.QtCore import QCoreApplication, QVariant
from qgis.core import (QgsProcessing, QgsProcessingAlgorithm,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterVectorDestination,
QgsWkbTypes, QgsFeatureRequest)
import processing
class ConvertPolygons(QgsProcessingAlgorithm):
INPUT = 'INPUT'
OUTPUT = 'OUTPUT'
def __init__(self):
super().__init__()
def name(self):
return "exportarpolygonos"
def tr(self, text):
return QCoreApplication.translate("exportarpolygonos", text)
def displayName(self):
return self.tr("Exportar Polygonos")
def group(self):
return self.tr("Examples")
def groupId(self):
return "examples"
def shortHelpString(self):
return self.tr("Exportar Polygonos")
def helpUrl(self):
return "https://qgis.org"
def createInstance(self):
return type(self)()
def checkParameterValues(self, parameters, context):
source = self.parameterAsSource(parameters, self.INPUT, context)
if source is None or QgsWkbTypes.geometryType(source.wkbType()) != QgsWkbTypes.PolygonGeometry:
return False, self.tr('Invalid input source. Expected a polygon layer.')
return super().checkParameterValues(parameters, context)
def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(
self.INPUT,
self.tr("Input polygons"),
[QgsProcessing.TypeVectorPolygon]))
self.addParameter(QgsProcessingParameterVectorDestination(
self.OUTPUT,
self.tr('Output lines')))
def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context).materialize(QgsFeatureRequest())
results = {}
outputs = {}
feedback.setProgressText('Converting polygons to lines...')
outputs['converted_lines'] = processing.run("native:polygonstolines",
{'INPUT':source, 'OUTPUT':parameters['OUTPUT']},
context=context,
feedback=feedback,
is_child_algorithm=True)
results['OUTPUT'] = outputs['converted_lines']['OUTPUT']
return results
-
Great answer! Can you please explain a bit what the
super()
actually does in this statementsuper().getParameterValues(parameters, context)
?2023年08月25日 06:34:36 +00:00Commented Aug 25, 2023 at 6:34 -
1Hi @Taras! I have expanded my answer a bit :-)Ben W– Ben W2023年08月25日 07:57:50 +00:00Commented Aug 25, 2023 at 7:57
-
Still not working. Now Qgis raised the same error, 'Unable to execute algorithm Could not load source layer for INPUT: invalid value'Luiz Paulo Zampronio– Luiz Paulo Zampronio2023年08月29日 18:14:12 +00:00Commented Aug 29, 2023 at 18:14
-
@Luiz Paulo Zampronio, see my updated answer with a full working example.Ben W– Ben W2023年08月30日 00:16:09 +00:00Commented Aug 30, 2023 at 0:16
Explore related questions
See similar questions with these tags.