4

I've been searching the web with no luck. This old exchange should be exactly what I need: Merging vector layers via python in QGIS 2.18.1

My code looks like this:

processing.tools.general.runalg("qgis:mergevectorlayers", importLayer + ";" + masterLayer, tempLayer)

But it gives the following error on execution:

TypeError: unsupported operand type(s) for +: 'QgsVectorLayer' and 'str' 
Traceback (most recent call last):
File "C:/Users/visitor/.qgis2/python/plugins\DataImporter\ImporterMain.py", line 47, in run self.dialog.run(layer)
File "C:/Users/visitor/.qgis2/python/plugins\DataImporter\ImporterUIFunctions.py", line 66, in run
self.mergeLayersIntoTemp(layer, layer.masterLayer)
File "C:/Users/visitor/.qgis2/python/plugins\DataImporter\ImporterUIFunctions.py", line 141, in mergeLayersIntoTemp
processing.tools.general.runalg("qgis:mergevectorlayers", importLayer + ";" + masterLayer, tempLayer)
TypeError: unsupported operand type(s) for +: 'QgsVectorLayer' and 'str'

Both importLayer and masterLayer are QgsVectorLayer objects, so I can only conclude it dislikes adding the ; in this fashion.

How is one supposed to send the layers to be merged these days?

EDIT:

The full code

def mergeLayersIntoTemp(self, importLayer, masterName):
    masterLayer = Utils.getLayerByName(masterName)
    tempLayerName = masterName + "_temp"

    tempLayer = ""
    provider = ""
    if not Utils.getLayerByName(tempLayerName):
        tempLayer = QgsVectorLayer("Point?crs=epsg:4326&index=yes", tempLayerName, "memory")
        provider = tempLayer.dataProvider()
    else: # We already have a temp player of this name. Something's wrong.
        ctypes.windll.user32.MessageBoxW(0, u"Attempted to create duplicate temporary layer.", u"Error", 0x0|0x10)
        return

    tempLayer.startEditing()

    #for field in masterLayer.pendingFields():
        #name = field.name()
        #fieldType = field.typeName()
        #provider.addAttributes([QgsField(name, getattr(QVariant, fieldType))])

    tempLayer.commitChanges()
    QgsMapLayerRegistry.instance().addMapLayer(tempLayer)


    Processing.initialize()
    processing.tools.general.runalg("qgis:mergevectorlayers", [importLayer, masterLayer], tempLayer)

def getLayerByName(name):
    layers = QgsMapLayerRegistry.instance().mapLayersByName(name)
    if layers:
        return layers[0]

importLayer is passed through from the top, it's the layer selected when the tool is run. This is a plugin, not console.

  • Layers must be separated by '+' characters. – xunilk Aug 11 '17 at 12:58
  • Can you specify which QGIS version you are using please? – Joseph Aug 11 '17 at 13:02
  • I use QGIS 2.18.11. – xunilk Aug 11 '17 at 13:05
1

I think the more recent QGIS versions require putting your layers into a list (i.e. [importLayer,masterLayer]). So you could try:

processing.tools.general.runalg("qgis:mergevectorlayers", [importLayer,masterLayer], tempLayer)

Edit:

The Processing algorithm already creates a temporary layer so there's no need to create one before running the algorithm. Instead, you can call the output for this and then modify it and add it to the interface:

Processing.initialize()

result = processing.tools.general.runalg("qgis:mergevectorlayers", [importLayer,masterLayer], None)
tempLayer = processing.getObject(result['OUTPUT'])

tempLayer.startEditing()
#for field in masterLayer.pendingFields():
    #name = field.name()
    #fieldType = field.typeName()
    #provider.addAttributes([QgsField(name, getattr(QVariant, fieldType))])

tempLayer.commitChanges()
QgsMapLayerRegistry.instance().addMapLayer(tempLayer)

Tested on QGIS 2.18.2 for Win7 64-bit.

  • Thanks for the feedback. Unfortunately this leads to a new error: 'QgsVectorLayer' object has no attribute '__getitem__' See log for more details There is nothing of interest in the log. – IceDreamer Aug 11 '17 at 12:27
  • 1
    @IceDreamer - Can you please edit your question to include the code snippet you used (i.e. how you defined your layers etc). And are you running this from a standalone script or from the QGIS Python Console? – Joseph Aug 11 '17 at 12:31
  • Edit made. Hope it helps us get to the bottom of this. – IceDreamer Aug 11 '17 at 12:41
  • @Joseph Layers must be separated by '+' characters; not in list. – xunilk Aug 11 '17 at 12:59
  • @xunilk - There may be a version conflict here. My method works for me using QGIS 2.18.2 whereas your method for QGIS 2.18.11 does not work... – Joseph Aug 11 '17 at 13:01
1

I tried this code in my system and it worked:

import processing

registry = QgsMapLayerRegistry.instance()

polygon1 = registry.mapLayersByName('polygon1')
polygon8 = registry.mapLayersByName('polygon8')

processing.runandload('qgis:mergevectorlayers',
                      polygon1 + polygon8,
                      None)

Layers must be separated by '+' characters. This was the successful result:

enter image description here

Editing Note:

This is another alternative version of code that works:

import processing

registry = QgsMapLayerRegistry.instance()

polygon1 = registry.mapLayersByName('polygon1')
polygon8 = registry.mapLayersByName('polygon8')

processing.runandload('qgis:mergevectorlayers',
                      [polygon1[0]] + [polygon8[0]],
                      None)
  • No joy. For my current layer definitions I get an unsupported operand type(s) for +: 'QgsVectorLayer' and 'QgsVectorLayer'. If I change it to fetch the master layer by mapLayersByName(name) rather than mapLayersByName()[0], I get the same error between 'QgsVectorLayer' and 'list'. Unsupported operand. Python script really, really doesn't like combining the args... – IceDreamer Aug 11 '17 at 13:06
  • As said Joseph, it looks like a version conflict here. For me works perfectly. – xunilk Aug 11 '17 at 13:09
  • Looks like I'm running the same version as you, so that can't be it. I am a bit confused how your code works. Because you're not calling the [0] index on the mapLayersByName(), surely your version sent lists of layers, rather than actual layers? – IceDreamer Aug 11 '17 at 13:10
  • I closed my QGIS and opened it again to run script. I got same successful result. – xunilk Aug 11 '17 at 13:15
  • See my Editing Note. In that code I'm calling the [0] index on the mapLayersByName() and it works too. – xunilk Aug 11 '17 at 13:19
1

The hint was in xunilk not fetching his layers, but an index containing each layer.

The successful syntax appears to be:

processing.tools.general.runalg("qgis:mergevectorlayers", [list1] + [list2], destination)

Lists. Not layers. This needs documenting somewhere...

As a side note, while my code now completes with no errors, using None as the final output, I don't get a "Merged" layer output like xunilk did. What is supposed to happen with that flag?

  • Because I'm using 'runandload' method (it loads layer automatically). With 'runalg' doesn't. – xunilk Aug 11 '17 at 13:23

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.