I am currently trying to convert a python script from QGIS 2.18 to QGIS 3. Therefore, I am trying to integrate my python script into the template from @underdark: see here.
I am currently stepping from one error into another so I seek help as I was not able to find any other question on Stack Exchange or any documentation.
Here is some part of my script so far:
def processAlgorithm(self, parameters, context, feedback):
inEdges = self.parameterAsVectorLayer(parameters, self.INPUT_VECTOR_LAYER_EDGES, context)
inNodes = self.parameterAsVectorLayer(parameters, self.INPUT_VECTOR_LAYER_NODES, context)
outMerged = self.parameterAsOutputLayer(parameters, self.OUTPUT_VECTOR_LAYER_MERGED, context)
#DO SOME CALCULATION
# get field indices for inputlayer
idxEdgeId = inEdges.fieldNameIndex(ID)
idxPriority = inEdges.fieldNameIndex(PRIORITY)
idxLength = inEdges.fieldNameIndex(LENGTH)
idxTime = inEdges.fieldNameIndex(TIME)
idxFrom = inEdges.fieldNameIndex(FROM)
idxTo = inEdges.fieldNameIndex(TO)
idx_id = inNodes.fieldNameIndex(NODEID)
idx_x = inNodes.fieldNameIndex(COORD_X)
idx_y = inNodes.fieldNameIndex(COORD_Y)
# Set the provider to accept the data source
outdp = outMerged.dataProvider()
# define attributes and add them to the vector layer
outdp.addAttributes([QgsField(EDGEID, QVariant.String),
QgsField(NODE1, QVariant.String),
QgsField(NODE2, QVariant.String),
QgsField(PRIORITY, QVariant.Int),
QgsField(VTO, QVariant.Double),
QgsField(VFROM, QVariant.Double)])
outMerged.updateFields()
# get field indices for outputlayer
outEdgeId = outdp.fieldNameIndex(EDGEID)
outNode1 = outdp.fieldNameIndex(NODE1)
outNode2 = outdp.fieldNameIndex(NODE2)
outPriority = outdp.fieldNameIndex(PRIORITY)
outVTo = outdp.fieldNameIndex(VTO)
outVFrom = outdp.fieldNameIndex(VFROM)
listOfEdgeIds = []
count = 0
flag = 0
(...)
For your information: I have two input vector layers (one point, and one line layer) and out of that, I want to create one outputlayer (which should be a line-vector layer as well).
But currently I have trouble with the fieldNameIndex(QString)
- method in the first section of the code. I have already tried to call the method with the dataProvider()
of the input layer, but that hasn't worked out. I get error:
Traceback (most recent call last): File "C:\Users\tlichten\AppData\Roaming\QGIS\QGIS3\profiles\default\processing\scripts\merging.py", line 89, in processAlgorithm idxEdgeId = inEdges.fieldNameIndex(ID) AttributeError: 'NoneType' object has no attribute 'fieldNameIndex'
Although I have to input vector layers, I cannot select any of them if I want to start the script. The execute script window looks like this:
In QGIS2.18, there would be two drop-down menus in which to choose between the input layers.
I have adapted the initAlgorithm()
to the following:
def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterVectorLayer(
self.INPUT_VECTOR_LAYER_EDGES,
self.tr('Edges'),
[QgsProcessing.TypeVectorAnyGeometry]))
self.addParameter(QgsProcessingParameterRasterLayer(
self.INPUT_VECTOR_LAYER_NODES,
self.tr('Nodes')
[QgsProcessing.TypeVectorAnyGeometry]))
self.addParameter(QgsProcessingParameterRasterDestination(
self.OUTPUT_VECTOR_LAYER_MERGED,
self.tr("Output Vector Layer Merged"),
[QgsProcessing.TypeVectorAnyGeometry]))
But I can still not select any input layers if I execute the script.
-
I have shortened the code segment. The error message I receive when trying to execute the script is as follows: Traceback (most recent call last): File "C:\Users\tlichten\AppData\Roaming\QGIS\QGIS3\profiles\default\processing\scripts\merging.py", line 89, in processAlgorithm idxEdgeId = inEdges.fieldNameIndex(ID) AttributeError: 'NoneType' object has no attribute 'fieldNameIndex'applebrown– applebrown2018年11月26日 13:11:38 +00:00Commented Nov 26, 2018 at 13:11
-
I have edited my question. Please see above. How do I select the layer in the input field. If I run the script from the toolbox I cannot select any inputlayer as it was with QGIS 2.18. I can just press start...applebrown– applebrown2018年11月26日 13:45:51 +00:00Commented Nov 26, 2018 at 13:45
-
Your code snippet is different than the sourced example you reference. That one uses a class which gets the parameters.artwork21– artwork212018年11月26日 14:03:37 +00:00Commented Nov 26, 2018 at 14:03
-
in initAlgorithm() functionartwork21– artwork212018年11月26日 14:41:58 +00:00Commented Nov 26, 2018 at 14:41
-
1You can't mix "Raster" and "Vector" in one parameter definition (your INPUT_VECTOR_LAYER_NODES name suggest it should be a vector not a raster) . Do you need Raster input or output? For output you should call self.addOutput.barteksch– barteksch2018年11月26日 15:12:36 +00:00Commented Nov 26, 2018 at 15:12
3 Answers 3
That method has been deprecated, use this instead to get the field index:
fields = inEdges.fields()
idxEdgeId = fields.indexFromName('fieldName')
-
thank you for your answer, I have tried your solution, but it looks like the fields() method is not known. This is my error now: Traceback (most recent call last): File "C:\Users\tlichten\AppData\Roaming\QGIS\QGIS3\profiles\default\processing\scripts\merging.py", line 89, in processAlgorithm fields = inEdges.fields() AttributeError: 'NoneType' object has no attribute 'fields'applebrown– applebrown2018年11月26日 13:30:47 +00:00Commented Nov 26, 2018 at 13:30
-
How/where is the processAlgorithm() being called? The vector layer "inEdges" is not valid.artwork21– artwork212018年11月26日 13:38:10 +00:00Commented Nov 26, 2018 at 13:38
-
I have edited the question. Please have a look! Thank you so muchapplebrown– applebrown2018年11月26日 14:24:44 +00:00Commented Nov 26, 2018 at 14:24
-
is the newFeature.setAttribute() method deprecated as well?? How can I set an attribute of a new feature for the output layer?applebrown– applebrown2018年11月26日 15:40:45 +00:00Commented Nov 26, 2018 at 15:40
-
1That method should still work. The referenced blog you noted in your question shows how to do that. Also, that question is different from this question so you should post a new question about that.artwork21– artwork212018年11月26日 17:09:05 +00:00Commented Nov 26, 2018 at 17:09
fieldNameIndex function was removed in QGIS3:
Removed fieldNameIndex(), use fields().lookupField() or fields().indexFromName() instead
You can convert your code as follows:
inEdges = self.parameterAsVectorLayer(parameters, self.INPUT_VECTOR_LAYER_EDGES, context)
inEdgesFields = inEdges.fields()
idxEdgeId = inEdgesFields.indexFromName(ID)
For more details see https://qgis.org/api/api_break.html
Exception you've got, suggest that you have problem with parameters, make sure you add parameters with proper key in initAlgorithm function (in QGIS2 it was defineCharacteristics):
def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterVectorLayer(self.INPUT_VECTOR_LAYER_EDGES, self.tr('Edges'), types=[QgsProcessing.TypeVector]))
-
thank you for your answer, I have tried your solution, but it looks like the fields() method is not known. This is my error now: Traceback (most recent call last): File "C:\Users\tlichten\AppData\Roaming\QGIS\QGIS3\profiles\default\processing\scripts\merging.py", line 90, in processAlgorithm inEdgesFields = inEdges.fields() AttributeError: 'NoneType' object has no attribute 'fields'applebrown– applebrown2018年11月26日 13:31:17 +00:00Commented Nov 26, 2018 at 13:31
-
Make sure the parameters are properly added in initAlgorithm(self, config=None) function and you select valid layer in the input fieldbarteksch– barteksch2018年11月26日 13:39:36 +00:00Commented Nov 26, 2018 at 13:39
-
the initAlgorithm method should work properly. But how do I select the layer in the input field. If I run the script from the toolbox I cannot select any inputlayer as it was with QGIS 2.18. I can just press start...applebrown– applebrown2018年11月26日 13:42:36 +00:00Commented Nov 26, 2018 at 13:42
-
I have edited my question. Please have a look for better understanding :)applebrown– applebrown2018年11月26日 13:46:23 +00:00Commented Nov 26, 2018 at 13:46
-
See my edited answerbarteksch– barteksch2018年11月26日 13:48:55 +00:00Commented Nov 26, 2018 at 13:48
Alternatively, there is also a possibility of using the indexOf(fieldName: str)
method.
from qgis.utils import iface
layer = iface.activeLayer()
fields = layer.fields()
fields_indxs = [fields.indexOf(field.name()) for field in fields]
Explore related questions
See similar questions with these tags.