2

Inspired by this question, but for QGIS 3 (and therefore Python 3), I would like to use the QGIS processing algorithms in a standalone Python script without a GUI, with a standard installation of Ubuntu Linux.

A simple import processing is insufficient:

import processing
processing.run(
   "qgis:rasterlayerstatistics",
   {
       'INPUT': .'/somefile.tif',
       'BAND': 1,
       'OUTPUT_HTML_FILE': './result.html'
   }
)

Results in:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'processing'

How do you get access to the QGIS processing module to use the QGIS processing algorithms in a standalone Python script (not the QGIS interpreter)?

3

This is an example of getting access to processing to run the QGIS "raster statistics" process, which returns useful information about a raster layer. In particular, raster statistics is useful for obtaining the sum of all values in a raster, which (AFAIK) cannot be done in GDAL alone.

#!/usr/bin/env python3
import os
import sys
import warnings
from functools import wraps


def ignore_warnings(f):
    @wraps(f)
    def inner(*args, **kwargs):
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("ignore")
            response = f(*args, **kwargs)
        return response
    return inner


def import_qgis_processing():
    sys.path.append('/usr/lib/qgis')
    sys.path.append('/usr/share/qgis/python/plugins')
    from qgis.core import QgsApplication, QgsProcessingFeedback, QgsRasterLayer
    app = QgsApplication([], False)
    feedback = QgsProcessingFeedback()
    return (app, feedback, QgsRasterLayer)


app, feedback, QgsRasterLayer = import_qgis_processing()
app.initQgis()


@ignore_warnings # Ignored because we want the output of this script to be a single value, and "import processing" is noisy
def initialise_processing(app):
    from qgis.analysis import QgsNativeAlgorithms
    import processing
    from processing.core.Processing import Processing
    Processing.initialize()
    app.processingRegistry().addProvider(QgsNativeAlgorithms())
    return (app, processing,)


def check_input_validity(QgsRasterLayer):
    raster = QgsRasterLayer(sys.argv[1], 'raster', 'gdal')
    if not raster.isValid():
        raise Exception('Invalid raster')


def raster_stats():
    params = {
        'INPUT': sys.argv[1],
        'BAND': 1
    }
    return processing.run(
        "qgis:rasterlayerstatistics",
        params, feedback=feedback
    )


def get_raster_stat(stat='SUM'):
    return raster_stats().get(stat)


app, processing = initialise_processing(app)
check_input_validity(QgsRasterLayer)
print(get_raster_stat(stat=sys.argv[2]))
app.exitQgis()

The ignore_warnings wrapper function is included because without it there are three deprecation warnings emitted when importing processing, and I wanted the script to have a simple output to stdout. You can leave that out if desired.

Importing modules within functions is done to control the order of import, and to stop linters (e.g. autopep8) from attempting to move all import statements to the top.

The key places to include in sys.path are:

  • /usr/lib/qgis
  • /usr/share/qgis/python/plugins

These would be different on different operating systems, and probably in different Linux distributions.

This script can be run like: ./rasterstats.py ./somefile.tif SUM, and it would output the sum of all values in the raster to stdout (ignoring no-data values if present). MAX, MIN, etc. work also.

The key functions are import_qgis_processing and initialise_processing.

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.