3

I'd like to automate a layer rasterization process using PyQGIS but the first step---obtaining a list of the layers to rasterize---is failing in QGIS 2.18.9 on Windows 10. What am I missing? Regardless of which project it's pointed to or whether Python is running from an IDE or the OSGeo4W shell directly the test script below always indicates zero layers even though project.read() always returns true.

import sys
sys.path.append('C:/Program Files/QGIS 2.18/apps/qgis/python')

from qgis.core import *
from PyQt4.QtCore import QFileInfo
qgis = QgsApplication([], False)
# EDIT: setPrefixPath() resolves the issue per Germán Carrillo's answer below
qgis.setPrefixPath('C:/Program Files/QGIS 2.18/apps/qgis', True)
qgis.initQgis()

project = QgsProject.instance()
project.read(QFileInfo('C:/Users/<username>/Documents/<path>/<project>.qgs'))

layers = project.layerTreeRoot()
print len(layers.children()), "layers loaded"

qgis.exitQgis()

I'm aware of this question and the code above conforms to a number of other similar examples which are supposed to work. Using QgsApplication([], True) or various other flavours of the above calls makes no difference. QgsMapLayerRegistry.instance().mapLayers() is also empty.

If the same projects are opened in the regular QGIS UI querying:

QgsProject.instance().layerTreeRoot().children() 

from the Python console contains all layers as expected. Having the project open in QGIS proper versus not having QGIS running has no effect on the external Python python behavior. So this doesn't look like contention between QGIS instances.

1
  • Issue is because your 'layers' is really an QgsLayerTreeGroup object.
    – xunilk
    Commented Jul 3, 2017 at 16:18

2 Answers 2

4

Issue is because your 'layers' is really an QgsLayerTreeGroup object. In my next example, you can observe how to retrieve all layers.

from PyQt4.QtCore import QFileInfo

project = QgsProject.instance()
project.read(QFileInfo('/home/zeito/Desktop/my_project.qgs'))

group = project.layerTreeRoot().children()

layers = [ item.layer() for item in group ]

print layers

I got all QgsVectorLayer objects:

[<qgis._core.QgsVectorLayer object at 0xa639bfa4>, <qgis._core.QgsVectorLayer object at 0xa639bd64>, <qgis._core.QgsVectorLayer object at 0xa639bdf4>, <qgis._core.QgsRasterLayer object at 0xa639bdac>, <qgis._core.QgsVectorLayer object at 0xa639be3c>]
2
  • I disagree. Even if you only have a group in your layers panel, the script provided in the question body should return a number other than zero. That's the problem exposed by the question: length of root's children should not be zero for non-empty QGIS projects. See my answer. Commented Jul 4, 2017 at 0:52
  • I can confirm. Curiously, this approach does find layer groups without a proper call to setPrefixPath() but I don't get any layers returned. It works fine with setPrefixPath() in place, however; appreciate the suggestion.
    – Todd West
    Commented Jul 4, 2017 at 5:16
2

You're only missing one line in your script to make it work properly. Namely, you need to set the prefix path for allowing QGIS to initialize data providers. So, right before the qgis.initQgis(), add this line:

qgis.setPrefixPath( qgis_prefix )

where qgis_prefix on my Windows machine is "C:/OSGeo4W64/apps/qgis/". On yours, it should be something like "C:/Program Files/QGIS 2.18/apps/qgis/". See this answer for tips on how to know what is your QGIS prefix path.

Once you do that, run your script and you won't obtain the 0 layers loaded message anymore using your project. With no prefix path, QGIS cannot create valid layers from your project, so they apparently aren't loaded.

3
  • By the way, on my Linux machine your original script works fine. It's only on Windows that I need to set the prefix path explicitly. Commented Jul 4, 2017 at 0:49
  • 1
    Practically, I almost always work on Linux. So, I didn't experience that issue. +1
    – xunilk
    Commented Jul 4, 2017 at 1:18
  • Thanks! I'd tried a few variants of calling setPrefixPath() but hadn't hit on the right combination of path and positioning of the call. Edited the initial script for clarity as to the correct approach.
    – Todd West
    Commented Jul 4, 2017 at 5:07

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