0

I wrote a small function to refactor fields (just one field really) in a given Shapefile which I output as a temporary layer. In principle it works just fine. I build a String with all the info the algorithm needs and when I input the String as a whole it works perfectly fine. However, when I hand over the String as variable I get a strange error (strange at least for me).

Here's my function:

def refactorFieldShp(self, sourceLayer, field_name):
        """
        Funktion zum Refactorn eines Feldes in einem Shapefile, hier: Vergrößern der Länge eines Textfelds
        based on https://gis.stackexchange.com/questions/302114/refactor-fields-using-pyqgis3
        """
        procString = "{'FIELDS_MAPPING':["
        fields_Shp = sourceLayer.fields()
        for field_Shp in fields_Shp:
            length = str(field_Shp.length())
            if field_name.casefold() == field_Shp.name().casefold() or field_name.casefold() == field_Shp.alias().casefold(): length = "254"
            procString += "{'expression': '\"" + field_Shp.name() + "\"','length': " + length + ",'name': '" + field_Shp.name() + "','precision': " + str(field_Shp.precision()) + ",'sub_type': 0,'type': " + str(field_Shp.type()) + ",'type_name': '" + field_Shp.typeName() + "'},"
        procString = procString[:-1] + "], 'INPUT':'" + sourceLayer.dataProvider().dataSourceUri() + "', 'OUTPUT':'TEMPORARY_OUTPUT'}"
        QgsMessageLog.logMessage("procString: " + procString, level=Qgis.Info)
        #copied from https://gis.stackexchange.com/questions/412691/adding-temporary-output-of-processing-algorithm-to-the-map-canvas-using-pyqgis
        processing.runAndLoadResults("qgis:refactorfields",procString)
        output = 'tbd'
        return output

This is the error I get:

Traceback (most recent call last):
File "C:\Users/Sickboy/AppData/Roaming/QGIS/QGIS3\profiles\default/python/plugins\writeout_xplan_columns\writeout_xplan_columns_algorithm.py", line 378, in processAlgorithm
last_index = self.setupColumnValues(sourceLayer, field_alias, last_index, sourceLayerDB, owComplex)
File "C:\Users/Sickboy/AppData/Roaming/QGIS/QGIS3\profiles\default/python/plugins\writeout_xplan_columns\writeout_xplan_columns_algorithm.py", line 291, in setupColumnValues
self.refactorFieldShp(sourceLayer,field_name)
File "C:\Users/Sickboy/AppData/Roaming/QGIS/QGIS3\profiles\default/python/plugins\writeout_xplan_columns\writeout_xplan_columns_algorithm.py", line 160, in refactorFieldShp
processing.runAndLoadResults("qgis:refactorfields",procString)
File "C:\PROGRA~1/QGIS32~2.3/apps/qgis/./python/plugins\processing\tools\general.py", line 144, in runAndLoadResults
p = parameters[param.name()]
TypeError: string indices must be integers

However if I copy the output of procString from console into the function like this:

def refactorFieldShp(self, sourceLayer, field_name):
        """
        Funktion zum Refactorn eines Feld in einem Shapefile, hier: Vergrößern der Länge eines Textfelds
        based on https://gis.stackexchange.com/questions/302114/refactor-fields-using-pyqgis3
        """
        QgsMessageLog.logMessage("field_name an refactorFieldShp() übergeben: " + field_name, level=Qgis.Info)
        procString = "{'FIELDS_MAPPING':["
        fields_Shp = sourceLayer.fields()
        for field_Shp in fields_Shp:
            length = str(field_Shp.length())
            if field_name.casefold() == field_Shp.name().casefold() or field_name.casefold() == field_Shp.alias().casefold(): length = "254"
            procString += "{'expression': '\"" + field_Shp.name() + "\"','length': " + length + ",'name': '" + field_Shp.name() + "','precision': " + str(field_Shp.precision()) + ",'sub_type': 0,'type': " + str(field_Shp.type()) + ",'type_name': '" + field_Shp.typeName() + "'},"
        procString = procString[:-1] + "], 'INPUT':'" + sourceLayer.dataProvider().dataSourceUri() + "', 'OUTPUT':'TEMPORARY_OUTPUT'}"
        QgsMessageLog.logMessage("procString: " + procString, level=Qgis.Info)
        #copied from https://gis.stackexchange.com/questions/412691/adding-temporary-output-of-processing-algorithm-to-the-map-canvas-using-pyqgis
        #processing.runAndLoadResults("qgis:refactorfields",{'FIELDS_MAPPING':[{'expression': '"gml_id"','length': 80,'name': 'gml_id','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"uuid"','length': 80,'name': 'uuid','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"text"','length': 80,'name': 'text','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"rechtsstan"','length': 80,'name': 'rechtsstan','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"gesetzlich"','length': 80,'name': 'gesetzlich','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"gliederung"','length': 80,'name': 'gliederung','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"gliederu_1"','length': 80,'name': 'gliederu_1','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"ebene"','length': 10,'name': 'ebene','precision': 0,'sub_type': 0,'type': 4,'type_name': 'Integer64'},{'expression': '"hatgenerat"','length': 80,'name': 'hatgenerat','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"hoehenanga"','length': 80,'name': 'hoehenanga','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"user_id"','length': 10,'name': 'user_id','precision': 0,'sub_type': 0,'type': 4,'type_name': 'Integer64'},{'expression': '"created_at"','length': 10,'name': 'created_at','precision': 0,'sub_type': 0,'type': 14,'type_name': 'Date'},{'expression': '"updated_at"','length': 10,'name': 'updated_at','precision': 0,'sub_type': 0,'type': 14,'type_name': 'Date'},{'expression': '"konvertier"','length': 10,'name': 'konvertier','precision': 0,'sub_type': 0,'type': 4,'type_name': 'Integer64'},{'expression': '"refbegruen"','length': 80,'name': 'refbegruen','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"gehoertzub"','length': 80,'name': 'gehoertzub','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"wirddarges"','length': 80,'name': 'wirddarges','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"externeref"','length': 254,'name': 'externeref','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"startbedin"','length': 80,'name': 'startbedin','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"endebeding"','length': 80,'name': 'endebeding','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"rechtschar"','length': 80,'name': 'rechtschar','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"wirdausgeg"','length': 80,'name': 'wirdausgeg','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"wirdausg_1"','length': 80,'name': 'wirdausg_1','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"wirdausg_2"','length': 80,'name': 'wirdausg_2','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"wirdausg_3"','length': 80,'name': 'wirdausg_3','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"wirdausg_4"','length': 80,'name': 'wirdausg_4','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"reftextinh"','length': 80,'name': 'reftextinh','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"flaechensc"','length': 1,'name': 'flaechensc','precision': 0,'sub_type': 0,'type': 2,'type_name': 'Integer'},{'expression': '"reflandsch"','length': 80,'name': 'reflandsch','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"ziel"','length': 80,'name': 'ziel','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"massnahme"','length': 80,'name': 'massnahme','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"refmassnah"','length': 80,'name': 'refmassnah','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"sonstziel"','length': 80,'name': 'sonstziel','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'},{'expression': '"inverszu_w"','length': 80,'name': 'inverszu_w','precision': 0,'sub_type': 0,'type': 10,'type_name': 'String'}], 'INPUT':'Z:/Christian/Arbeit/GDI-Service/xmi2db_2021/QGIS Forms/Testdaten/xplan_standard_shapes_befuellt/bp_ausgleichsflaeche.shp', 'OUTPUT':'TEMPORARY_OUTPUT'})
        output = 'tbd'
        return output

... it works fine. And no, I didn't change anything, I just copy pasted the console output and overwrote procString in the function call with it.

Any ideas what's wrong here or how to circumvent this issue?

1
  • 2
    Algorithm parameters should be a dictionary object not a string object. When you pass your procString variable, you are giving the parameters argument as a string which is incorrect. My guess is that when you copy and paste from the console it is being parsed correctly as a dictionary (without the enclosing double quotes).
    – Ben W
    Jul 24 at 13:23

1 Answer 1

0

Ben, after sleeping over it I came to the same conclusion but thanks so much for your hint anyway :-)

I really don't like Python dictionaries (esp. in conunction with arrays) but in case someone ever needs a function to refactor fields here it is:

def refactorFieldShp(self, sourceLayer, field_name):
    fieldsMapping = []
    fields_Shp = sourceLayer.fields()
    i = 0
    for field_Shp in fields_Shp:
        if field_name.casefold() == field_Shp.name().casefold() or field_name.casefold() == field_Shp.alias().casefold(): length = 254
        fieldsMapping.append({'expression': field_Shp.name(),'length': length,'name': field_Shp.name(),'precision': field_Shp.precision(),'sub_type': 0,'type': field_Shp.type(),'type_name': field_Shp.typeName()})
        i += 1
    procDict = {'FIELDS_MAPPING':fieldsMapping, 'INPUT': sourceLayer.dataProvider().dataSourceUri(), 'OUTPUT':'TEMPORARY_OUTPUT'}
    processing.runAndLoadResults("qgis:refactorfields",procDict)
    output = 'tbd'
    return output

(This function just copies all existing fields and leaves them as they are. It only changes the length of one field passed to the function as field_name.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.