9

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:

enter image description here

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.

Taras
  • 32,823
  • 4
  • 66
  • 137
applebrown
  • 725
  • 7
  • 24
  • 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 Nov 26 '18 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 Nov 26 '18 at 13:45
  • Your code snippet is different than the sourced example you reference. That one uses a class which gets the parameters. – artwork21 Nov 26 '18 at 14:03
  • in initAlgorithm() function – artwork21 Nov 26 '18 at 14:41
  • yea I have already updated it. But it still does not work . – applebrown Nov 26 '18 at 14:45
  • 1
    You 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 Nov 26 '18 at 15:12
  • Related topic: https://gis.stackexchange.com/questions/279934/attributeerror-qgsvectorlayer-object-has-no-attribute-fieldnameindex – Taras Nov 19 '22 at 11:49

3 Answers3

14

That method has been deprecated, use this instead to get the field index:

fields = inEdges.fields()
idxEdgeId = fields.indexFromName('fieldName')
artwork21
  • 35,114
  • 8
  • 66
  • 134
  • 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 Nov 26 '18 at 13:30
  • How/where is the processAlgorithm() being called? The vector layer "inEdges" is not valid. – artwork21 Nov 26 '18 at 13:38
  • I have edited the question. Please have a look! Thank you so much – applebrown Nov 26 '18 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 Nov 26 '18 at 15:40
  • 1
    That 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 Nov 26 '18 at 17:09
6

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]))
barteksch
  • 675
  • 4
  • 9
  • 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 Nov 26 '18 at 13:31
  • Make sure the parameters are properly added in initAlgorithm(self, config=None) function and you select valid layer in the input field – barteksch Nov 26 '18 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 Nov 26 '18 at 13:42
  • I have edited my question. Please have a look for better understanding :) – applebrown Nov 26 '18 at 13:46
  • See my edited answer – barteksch Nov 26 '18 at 13:48
  • I have edited the question. Please have a look. – applebrown Nov 26 '18 at 14:25
  • is the newFeature.setAttribute() method deprecated as well?? How can I set an attribute of a new feature for the output layer? – applebrown Nov 26 '18 at 15:40
1

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]

Taras
  • 32,823
  • 4
  • 66
  • 137