5

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.

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

3 Answers 3

2

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.

7
  • 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
    Commented Aug 11, 2017 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
    Commented Aug 11, 2017 at 12:31
  • Edit made. Hope it helps us get to the bottom of this.
    – IceDreamer
    Commented Aug 11, 2017 at 12:41
  • @Joseph Layers must be separated by '+' characters; not in list.
    – xunilk
    Commented Aug 11, 2017 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
    Commented Aug 11, 2017 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)
7
  • 1
    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
    Commented Aug 11, 2017 at 13:06
  • As said Joseph, it looks like a version conflict here. For me works perfectly.
    – xunilk
    Commented Aug 11, 2017 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
    Commented Aug 11, 2017 at 13:10
  • I closed my QGIS and opened it again to run script. I got same successful result.
    – xunilk
    Commented Aug 11, 2017 at 13:15
  • See my Editing Note. In that code I'm calling the [0] index on the mapLayersByName() and it works too.
    – xunilk
    Commented Aug 11, 2017 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?

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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