PyQGIS Standalone – Fix ‘qgis.processing’ Module No Attribute ‘run’ Issue

pyqgisqgis-processingstandalone

When trying to use processing.run() from a standalone (no GUI) mode, I get the following error:

module 'qgis.processing' has no attribute 'run'

in the following trivial example:


from qgis import processing
result = processing.run("native:buffer", {'INPUT': 'test', 'OUTPUT': 'memory:'})

Other methods, like algorithmHelp(), don't seem to work either.

I followed the Windows setup instructions from here:

https://docs.qgis.org/3.16/en/docs/pyqgis_developer_cookbook/intro.html#running-custom-applications

Setting the following environment vars:

PYTHONPATH=C:\OSGeo4W\apps\qgis\python

and PATH is appended with C:\OSGeo4W\bin;C:\OSGeo4W\apps\qgis\bin

Anything I'm missing here?

NOTE: When running the same script from inside the GUI (using the Script editor), all goes well and I don't get these errors. Somehow the environment seems to be different between the two.

QGIS version is 3.22.2-Białowieża.

Best Answer

You also need to add the following lines:

# To import section
from qgis.analysis import QgsNativeAlgorithms
from processing.core.Processing import Processing

...
...

# after qgs.initQgis() 
Processing.initialize()
QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms())

...
...

Sometimes developing a PyQGIS standalone application can be tiring. Especially for those new to this topic. You need to open your editor using a batch file like this:

@echo off
SET OSGEO4W_ROOT="C:\OSGeo4W"
call %OSGEO4W_ROOT%\bin\o4w_env.bat

path %PATH%;%OSGEO4W_ROOT%\apps\qgis\bin
path %PATH%;%OSGEO4W_ROOT%\apps\Qt5\bin
path %PATH%;%OSGEO4W_ROOT%\apps\Python39\Scripts
set QGIS_PREFIX=%OSGEO4W_ROOT%\apps\qgis
set PYTHONHOME=%OSGEO4W_ROOT%\apps\Python39
set PYTHONPATH=%OSGEO4W_ROOT%\apps\qgis\python;%OSGEO4W_ROOT%\apps\qgis\python\plugins;%PYTHONPATH%
set QT_QPA_PLATFORM_PLUGIN_PATH=%OSGEO4W_ROOT%\apps\Qt5\plugins\platforms
set QT_PLUGIN_PATH=%OSGEO4W_ROOT%\apps\qgis\qtplugins;%OSGEO4W_ROOT\apps\qt5\plugins

set GDAL_FILENAME_IS_UTF8=YES
set VSI_CACHE=TRUE
set VSI_CACHE_SIZE=1000000

start "Visual Studio QGIS" /B "C:\Program Files\Microsoft VS Code\Code.exe" %*

A working example here: (change source_path).

from qgis.core import *
from qgis.gui import *
from qgis.PyQt.QtWidgets import *

import processing
from qgis.analysis import QgsNativeAlgorithms
from processing.core.Processing import Processing


### GUI Construction ###
class MapViewer(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self, None)

        self._canvas = QgsMapCanvas()
        self._root = QgsProject.instance().layerTreeRoot()

        self.bridge = QgsLayerTreeMapCanvasBridge(self._root, self._canvas)
        self.model = QgsLayerTreeModel(self._root)
        self.model.setFlag(0x25043)
        self.model.setFlag(QgsLayerTreeModel.ShowLegend)
        self.layer_treeview = QgsLayerTreeView()
        self.layer_treeview.setModel(self.model)

        self.layer_tree_dock = QDockWidget("Layers")
        self.layer_tree_dock.setObjectName("layers")
        self.layer_tree_dock.setFeatures(QDockWidget.NoDockWidgetFeatures)
        self.layer_tree_dock.setWidget(self.layer_treeview)

        self.splitter = QSplitter()
        self.splitter.addWidget(self.layer_tree_dock)
        self.splitter.addWidget(self._canvas)
        self.splitter.setCollapsible(0, False)
        self.splitter.setStretchFactor(1, 1)

        self.layout = QHBoxLayout()
        self.layout.addWidget(self.splitter)
        self.contents = QWidget()
        self.contents.setLayout(self.layout)
        self.setCentralWidget(self.contents)

        self.load_layers()

    def load_layers(self):
        source_path = "path/to/data/source"
        layer = QgsVectorLayer(source_path, 'Layer1', 'ogr')
        QgsProject.instance().addMapLayer(layer)
        self._canvas.setExtent(layer.extent())
        self._canvas.setLayers([layer])

        ### PROCESSING
        result = processing.run("native:buffer", {'INPUT': source_path, 'DISTANCE':10, 'OUTPUT': 'memory:'})
        QgsProject.instance().addMapLayer(result["OUTPUT"])
########################
        
qgs = QgsApplication([], True)
qgs.initQgis()

Processing.initialize()
QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms())

main_window = MapViewer()
main_window.show()

qgs.exec_()
qgs.exitQgis()

enter image description here