I have a QGIS model that I want to modify with an IF personalised script.
Basically one of the inputs is optional, but if it's empty then the model is throwing some errors down the line. Hence the script would aim to check IF the input is empty, in which case would create and empty dummy shapefile, and use it on the rest of the calculations.
Below is the script that I've tested outside the graphic modeler, following the suggestions here QGIS Modeler if/else condition, custom script for Modeler
##Example=name
##DOB=optional raster
##output=output vector
if DOB is None:
fake_DOB = 'C:/Temp/fake_DOB.shp'
layerFields = QgsFields()
layerFields.append(QgsField('DOB', QVariant.Double))
output = QgsVectorFileWriter(fake_DOB, 'UTF-8', layerFields, QgsWkbTypes.Point,\
QgsCoordinateReferenceSystem(), 'ESRI Shapefile')
feat = QgsFeature()
feat.setAttributes(['',0])
output.addFeature(feat)
else:
output=DOB
However, it sort of works outside the graphic modeller environment, but as soon as I try to add it to the list of algorithms an error pops stating:
NameError: name 'QgsFields' is not defined
any ideas?
UPDATE: Since it was pointed out that I was using the wrong structure for QGIS 3.x I've been trying to 'translate' the code using the not-very-beginners-friendly template... unsuccessfully.
I'm now getting an error that I can't seem to solve. Ideas?
NameError: name 'QVariant' is not defined
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
QgsFeatureSink,
QgsProcessingException,
QgsProcessingAlgorithm,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsField,
QgsFields,
QgsProcessingParameterField,
QgsProcessingParameterVectorLayer)
from qgis import processing
class dummy_DOB(QgsProcessingAlgorithm):
INPUT = 'DOB'
OUTPUT = 'OUTPUT'
def tr(self, string):
"""
Returns a translatable string with the self.tr() function.
"""
return QCoreApplication.translate('Processing', string)
def createInstance(self):
return dummy_DOB()
def name(self):
return 'dummy_DOB'
def displayName(self):
return self.tr('dummy_DOB')
def group(self):
return self.tr('Scripts')
def groupId(self):
return 'Scripts'
def shortHelpString(self):
return self.tr("Creates a dummy DOB if empty")
def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT, 'DOB', optional=True, types=[QgsProcessing.TypeVectorPoint], defaultValue=None))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,self.tr('Output DOB layer')))
def processAlgorithm(self, parameters, context, feedback):
"""
Here is where the processing itself takes place.
"""
source = self.parameterAsSource(
parameters,
self.INPUT,
context
)
if source is None:
fake_DOB = 'C:/Temp/fake_DOB.shp'
layerFields = QgsFields()
layerFields.append(QgsField('DOB', QVariant.Double))
output = QgsVectorFileWriter(fake_DOB, 'UTF-8', layerFields, QgsWkbTypes.Point,\
QgsCoordinateReferenceSystem(), 'ESRI Shapefile')
feat = QgsFeature()
feat.setAttributes(['',0])
output.addFeature(feat)
else:
output=source
(sink, dest_id) = self.parameterAsSink(
parameters,
self.OUTPUT,
context,
source.fields(),
source.wkbType(),
source.sourceCrs()
)
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
return {self.OUTPUT: dest_id}
UPDATE:
I kept importing processes and applications.
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
QgsFeatureSink,
QgsProcessingException,
QgsProcessingAlgorithm,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsField,
QgsFields,
QgsWkbTypes,
QgsFeature,
QgsProcessingParameterField,
QgsVectorFileWriter,
QgsProcessingParameterVectorLayer,
QgsCoordinateReferenceSystem)
from qgis import processing
from PyQt5.QtCore import *
I have finally a different type of error:
File "", line 78, in processAlgorithm
AttributeError: 'NoneType' object has no attribute 'fields'
I think is related with the fact that I haven't stored any outputs in the sink. TBH I don't know how to do it, I just kept that part from the Template, I'm trying hard to make this work but I'm far from being an expert.
source = self.parameterAsSource(
parameters,
self.INPUT,
context
)
if source is None:
fake_DOB = 'C:/Temp/fake_DOB.shp'
layerFields = QgsFields()
layerFields.append(QgsField('DOB', QVariant.Double))
output = QgsVectorFileWriter(fake_DOB, 'UTF-8', layerFields, QgsWkbTypes.Point,\
QgsCoordinateReferenceSystem(), 'ESRI Shapefile')
feat = QgsFeature()
feat.setAttributes(['',0])
output.addFeature(feat)
else:
output=source
(sink, dest_id) = self.parameterAsSink(
parameters,
self.OUTPUT,
context,
source.fields(), ##line of the error
source.wkbType(),
source.sourceCrs()
)
if sink is None:
raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
return {self.OUTPUT: dest_id}
from PyQt4.QtCore import *