Carto Carto - 5 months ago 56
Python Question

Python Script with QGis - Python.exe Stopped Working

I purchased this book called Building Mapping Applications with QGIS and I am trying to work through one of the exercises. There is one script that I try to run that crashes python, generating the error message "python.exe has stopped working".

import sys
import os
from qgis.core import *
from qgis.gui import *
from PyQt4.QtGui import *
from PyQt4.QtCore import Qt



#############################################################################


class MapViewer(QMainWindow):
def __init__(self, shapefile):
QMainWindow.__init__(self)
self.setWindowTitle("Map Viewer")

canvas = QgsMapCanvas()
canvas.useImageToRender(False)
canvas.setCanvasColor(Qt.white)
canvas.show()

layer = QgsVectorLayer(shapefile, "layer1", "ogr")
if not layer.isValid():
raise IOError("Invalid shapefile")

QgsMapLayerRegistry.instance().addMapLayer(layer)
canvas.setExtent(layer.extent())
canvas.setLayerSet([QgsMapCanvasLayer(layer)])

layout = QVBoxLayout()
layout.addWidget(canvas)

contents = QWidget()
contents.setLayout(layout)
self.setCentralWidget(contents)

#############################################################################


def main():
""" Our main program.
"""
QgsApplication.setPrefixPath(os.environ['QGIS_PREFIX'], True)
QgsApplication.initQgis()

app = QApplication(sys.argv)

viewer = MapViewer("C:/folder/shapefile.shp")
viewer.show()

app.exec_()

QgsApplication.exitQgis()

#############################################################################

if __name__ == "__main__":
main()


I don't know a whole lot about Python with QGIS so I'm not too sure what is causing python to crash. I am positive that all of the modules are importing correctly because if I define my paths and then import the modules in the script using the OSGeo4W Shell, there are no error messages.

This is how my paths are defined:

SET OSGEO4W_ROOT=C:\OSGeo4W64
SET QGIS_PREFIX=%OSGEO4W_ROOT%\apps\qgis
SET PATH=%PATH%;%QGIS_PREFIX%\bin
SET PYTHONPATH=%QGIS_PREFIX%\python;%PYTHONPATH%


Given all of this, I think there has to be something wrong in the script. However, when I check the script using http://pep8online.com/ there are no errors that I can fix that will result in python not crashing.

Note that I have tried I have tried
SET PATH=%QGIS_PREFIX%\bin;%PATH%
instead of
SET PATH=%PATH%;%QGIS_PREFIX%\bin
with no success.

Answer

I was fortunate enough to get in touch with the author of the book so I will share his response here:

I suspect I may know what the problem is...after looking at this reader's problems in more depth, I've discovered that something has changed in newer versions of QGIS, and the example code no longer works as it is written. In technical terms, it seems that you now need to instantiate the QApplication object before making the call to QgsApplication.initQgis() -- the example program in the book instantiates the QApplication object after calling QgsApplication.initQgis(), which causes the program to crash. To fix this, change the main() function to look like the following:

def main():
    """  Our main program.
    """
    app = QApplication(sys.argv)
    QgsApplication.setPrefixPath(os.environ['QGIS_PREFIX'],True)
    QgsApplication.initQgis()

    viewer = MapViewer("C:/folder/shapefile.shp")
    viewer.show()

    app.exec_()

    QgsApplication.exitQgis()

As you can see, I've moved the "app = QApplication(sys.argv)" line to the top.

Important Note: Make sure that forward slashes are used in viewer = MapViewer("C:/folder/shapefile.shp") - using a backslash will result in an error message stating that the shapefile is invalid.

I also thought it would be worth mentioning that none of the above fixes (comments on the question) were necessary. So, the script will work if the paths are defined as follows:

SET OSGEO4W_ROOT=C:\OSGeo4W64
SET QGIS_PREFIX=%OSGEO4W_ROOT%\apps\qgis
SET PATH=%PATH%;%QGIS_PREFIX%\bin
SET PYTHONPATH=%QGIS_PREFIX%\python;%PYTHONPATH%

Then, the entire script looks like this:

import sys
import os
from qgis.core import *
from qgis.gui import *
from PyQt4.QtGui import *
from PyQt4.QtCore import Qt



#############################################################################


class MapViewer(QMainWindow):
    def __init__(self, shapefile):
        QMainWindow.__init__(self)
        self.setWindowTitle("Map Viewer")

        canvas = QgsMapCanvas()
        canvas.useImageToRender(False)
        canvas.setCanvasColor(Qt.white)
        canvas.show()

        layer = QgsVectorLayer(shapefile, "layer1", "ogr")
        if not layer.isValid():
            raise IOError("Invalid shapefile")

        QgsMapLayerRegistry.instance().addMapLayer(layer)
        canvas.setExtent(layer.extent())
        canvas.setLayerSet([QgsMapCanvasLayer(layer)])

        layout = QVBoxLayout()
        layout.addWidget(canvas)

        contents = QWidget()
        contents.setLayout(layout)
        self.setCentralWidget(contents)

#############################################################################


def main():
    """  Our main program.
    """
    app = QApplication(sys.argv)
    QgsApplication.setPrefixPath(os.environ['QGIS_PREFIX'],True)
    QgsApplication.initQgis()

    viewer = MapViewer("C:/folder/shapefile.shp")
    viewer.show()

    app.exec_()

    QgsApplication.exitQgis()

#############################################################################

if __name__ == "__main__":
    main()

Execute it in the OSGEO4W Shell using the following command:

python "C:\script.py"

Lastly, note that at the time of this writing, the script works properly and launches a viewer showing the shapefile referenced, but returns a few errors in the shell that do not seem to be problematic:

ERROR: Opening of authentication db FAILED
ERROR: Unable to establish authentication database connection
ERROR: Auth db could not be created and opened
QSqlDatabasePrivate::database: unable to open database: "unable to open database file Error opening database"
ERROR: Opening of authentication db FAILED

Much thanks to the author Erik Westra for providing me with this solution.