Friday 20 May 2016

qgis - Why the order of imports matters in a standalone PyQGIS processing script?


I've come across a weird issue while running standalone PyQGIS processing scripts. The order of imports in the script affects its normal execution.



You can reproduce the problem by opening a Python console and entering the following script (I use GNU/Linux, QGIS 2.6.1, processing plugin v.2.2.0-2, and Python 2.7.3):


# Prepare the environment
import sys
from qgis.core import QgsApplication
from PyQt4.QtGui import QApplication
app = QApplication([])
QgsApplication.setPrefixPath("/usr", True)
QgsApplication.initQgis()

# Prepare processing framework

sys.path.append('/home/YOUR_USER/.qgis2/python/plugins')
from processing.core.Processing import Processing
Processing.initialize()

print Processing.getAlgorithm("qgis:creategrid")

# Exit applications
QgsApplication.exitQgis()
QApplication.exit()


You should obtain:


ALGORITHM: Create grid
HSPACING
VSPACING
WIDTH
HEIGHT
CENTERX
CENTERY
GRIDTYPE
CRS

SAVENAME

On the other hand, if you switch the order of imports (lines 3 and 4), this way:


from PyQt4.QtGui import QApplication
from qgis.core import QgsApplication

the script now returns... None, because the algorithm was not found.


This issue implies that you cannot run processing algorithms out of QGIS if you (by chance) write imports in the wrong order.


I've checked in StackOverflow but according to Does Python import order matter, the order shouldn't really matter. Moreover, the Style Guide for Python Code tells us to import standard (more generic) libraries first, then related third party libraries, and finally, local application specific imports. I think PyQt4 lies in the 2nd category of imports, whereas PyQGIS would be local application specific, so PyQt4 imports should come first (I'm not an expert on this, though).


Do you have an idea of why this could happen? Have you ever experienced something similar?





EDIT 1: Changed implicit imports (from abc import *) by explicit ones (e.g., from abc import xyz) as suggested by @mike-t.



Answer



tl;dr


import qgis
import PyQt4
etc

is the correct way


Long version



Yes the import order can matter and in the case of QGIS 2.0 and above it does matter.


You should always import qgis.core or qgis.gui, even just import qgis is enough, before you import any PyQt stuff.


That seems silly. Why?


In QGIS 2.0 we switched to using version 2 bindings of SIP which made API calls more Python like e.g it will auto convert types for you:


1.0 SIP you had to do:


value.toString()

in 2.0


value


will just work if it's a string type in the C++ code.


Ok So what


The kicker is that we have to set the API version to 2 in code before it gets set my something else, you can't set it again once it's been set. If you import PyQt first it will set the value to v1 but everything in QGIS now uses v2. In order to fix this we set it to v2 in qgis.__init__.py but we have to import qgis first or else PyQt wins.


Because all of the plugins in QGIS 2.0 and above now use SIP v2 any SIP v1 like calls will generate a error when running.


No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...