3

I need to run a processing algorithm that is coded/called in different file than main file. I've read some posts (1, 2, 3, 4, 5) but they give a solution that runs algorithm in main file. When I use those examples, algorithms work.

But I have three files for standalone QGIS application. The application has a window which includes a layer tree, a map canvas and a button (the following image). The button calls a method, defined in another file, which includes calling a processing algorithm. When I click the button, I get an error: For example: Error: Algorithm native:buffer not found.

enter image description here

I couldn't figure out how/where to add the next lines of code which is presented as a solution.

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

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

Minimal files' structure:

enter image description here

Example Files:

main.py

import os
import sys
from qgis.core import *
from qgis.PyQt.QtWidgets import QApplication
from qgis.analysis import QgsNativeAlgorithms
import processing
from processing.core.Processing import Processing

from viewer import Viewer

QgsApplication.setPrefixPath(os.environ['QGIS_PREFIX_PATH'], True)
qgs = QgsApplication([], True)
qgs.initQgis()

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

# The algorithm works here, but doesn't work in funcs_.py
# params = {...}
# buf = processing.run("native:buffer", params)

app = QApplication(sys.argv)
main_window = Viewer()
main_window.show()
sys.exit(app.exec_())
qgs.exitQgis()

viewer.py

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

import funcs_

class Viewer(QMainWindow):

    def __init__(self):
        QMainWindow.__init__(self, None)
        self.initGUI()

    def initGUI(self):
        self.canvas = QgsMapCanvas()
        self.layer = QgsVectorLayer("shapefile_path", 'Layer1', 'ogr')
        QgsProject.instance().addMapLayers([self.layer])

        self.layout = QHBoxLayout()
        self.root = QgsProject.instance().layerTreeRoot()
        self.bridge = QgsLayerTreeMapCanvasBridge(self.root, self.canvas)
        self.model = QgsLayerTreeModel(self.root)

        self.model.setFlag(QgsLayerTreeModel.AllowNodeChangeVisibility)
        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.setWidget(self.layer_treeview)

        self.button = QPushButton("Create Buffer")
        self.button.clicked.connect(self._create_buffer)

        self.splitter = QSplitter()
        self.splitter.addWidget(self.layer_tree_dock)
        self.splitter.addWidget(self.canvas)
        self.splitter.addWidget(self.button)

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

    def _create_buffer(self):
        lyr = funcs_.create_buffer(self.layer)
        QgsProject.instance().addMapLayers([lyr])

func_.py

import processing

def create_buffer(lyr):
    params = {'INPUT':lyr, 'DISTANCE':15, 'OUTPUT':'memory:'}    
    buf = processing.run("native:buffer", params)

    return buf["OUTPUT"]
  • 2
    Just tested your code. For me the buffer alg runs well but I needed to change something in main.py: Comment or remove lines involving app (i.e., app = QApplication(sys.argv) and sys.exit(app.exec_())). Instead, use qgs.exec_() right before qgs.exitQgis(). In that way everything works fine. – Germán Carrillo Jan 7 at 14:01
  • Additionally, a sys.path.append('/path/to/python/plugins/folder') may be required before importing processing. As stated in gis.stackexchange.com/questions/279874/… – Germán Carrillo Jan 7 at 14:09