4

I'm trying to get to a piece of code that lets me print PDF maps with the PYQGIS API using a workspace and a template.

This code does the job, but throws an error, stopping me from lining up consecutive maps to be produced.

sys.path.append('/Applications/QGIS.app/Contents/Resources/python')
import os
from qgis.core import (
    QgsProject, QgsComposition, QgsApplication, QgsProviderRegistry)
from qgis.gui import QgsMapCanvas, QgsLayerTreeMapCanvasBridge
from PyQt4.QtCore import QFileInfo
from PyQt4.QtXml import QDomDocument
from qgis.core import *

def make_pdf():
    project_path = 'project.qgs'
    template_path = 'template.qpt'
    gui_flag = True
    QgsApplication.setPrefixPath("/Applications/QGIS.app/Contents/Resources/python", True)
    app = QgsApplication(sys.argv, gui_flag)
    app.setPrefixPath("/Applications/QGIS.app/Contents/MacOS", True)
    app.initQgis()
    canvas = QgsMapCanvas()
    QgsProject.instance().read(QFileInfo(project_path))
    bridge = QgsLayerTreeMapCanvasBridge(
    QgsProject.instance().layerTreeRoot(), canvas)
    bridge.setCanvasLayers()
    template_file = file(template_path)
    template_content = template_file.read()
    template_file.close()
    document = QDomDocument()
    document.setContent(template_content)
    composition = QgsComposition(canvas.mapSettings())
    composition.loadFromTemplate(document, {})
    composition.refreshItems()
    composition.exportAsPDF('output.pdf')
    QgsProject.instance().clear()

The output is:

QSqlDatabase: QSQLITE driver not loaded
QSqlDatabase: available drivers: 
QSqlQuery::prepare: database not open
ERROR: Opening of authentication db FAILED
WARNING: Auth db query exec() FAILED
Loading a file that was saved with an older version of qgis (saved in  2.12.1-Lyon, loaded in 2.16.3). Problems may occur.
QObject::startTimer: QTimer can only be used with threads started with    QThread

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)

That SIGSERV error at end seems pretty nasty - but I'm no where near understanding what's going on when I Google that.

4
  • Sigsegv is a segmentation fault, also known as a crash. The very first thing to do is to isolate the line on which it happens. The easiest way to do so is printing debug messages and check to which command you get. – Matthias Kuhn Nov 20 '16 at 12:22
  • Funnily enough I've just been trying that - however the error prints at after the function has run - i.e. I have "print 'END'" as my final line, end the output reads END \r Process finished with exit code 139 (interrupted by signal 11: SIGSEGV) – Ben Mayo Nov 20 '16 at 12:55
  • if it was just that, you'd not need to worry. at that point you've got your pdf. are you calling it in a loop? – Matthias Kuhn Nov 20 '16 at 13:14
  • Yes, that's the idea - many different PDF maps to produce. – Ben Mayo Nov 20 '16 at 13:53
3

Segmetation faults

A segmentation fault (SIGSEGV) is a very generic failure that indicates the application has crashed. Just from the message it's impossible to tell what exactly has gone wrong.

If the crash happens at the very end, when the application is exiting (which seems to be a possible scenario here), it might also be valid to just accept it.

Debugging

To investigate the problem you will need to identify where exactly it happens. There are different possibilities how to do this:

  • Add print statements and check until where the application is executed
  • Use a debugger (like gdb or llvm), this gives much insight into what exactly happens, but is also more complex to set up and requires a good expertise to properly interpret.
  • Depending on the system and its configuration you might also be able to get a backtrace from the crash, which also gives good hints on what happens. Explaining this in detail would be out of scope for this question.

Hints for your code

Some notes about your code

  • There should only be one QgsApplication which should exist throughout the whole lifetime of the application
  • This QgsApplication instance should be initialized only once
  • There is also always just one QgsProject (it's a singleton). There can be several QgsMapCanvas but I'm not sure if that's required for your use case. (Note, this will probably change with QGIS 3, where multiple projects can exist in parallel)
  • There is also a method app.exitQgis() which cleans up resources in the end (and might fix crashes on exit sometimes)
  • Don't use *-imports. It's not introducing any problems here, but it's bad practise. For example, it will be easier to upgrade your code to QGIS 3.0 if you are using explicit imports.

In short: initialize QGIS once, loop only over the mapping and export code itself.

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.