Skip to main content
added 3197 characters in body
Source Link
Ben W
  • 23.1k
  • 3
  • 19
  • 43

Based on further clarification in comments, I tested running this as standalone script from the command line (with pyqgis environment properly set) and it worked fine for me using the script below (with my own paths of course).

# See https://gis.stackexchange.com/questions/279874/using-qgis-3-processing-algorithms-from-pyqgis-standalone-scripts-outside-of-gu
import sys

import os

from qgis.core import (
     QgsApplication, 
     QgsCoordinateReferenceSystem,
     QgsProject,
     QgsProcessingFeatureSourceDefinition,
     QgsFeatureRequest
)
from qgis.analysis import QgsNativeAlgorithms

# See https://gis.stackexchange.com/a/155852/4972 for details about the prefix 
QgsApplication.setPrefixPath('C:/OSGeo4W/apps/qgis', True)
qgs = QgsApplication([], False)
qgs.initQgis()

# Append the path where processing plugin can be found
sys.path.append('C:\\OSGeo4W\\apps\\qgis\\python\\plugins')

import processing
from processing.core.Processing import Processing
Processing.initialize()
QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms())

sourceFiles = ['D:\\Path\\To\\Some\\Shapefiles\\Source_File_1.shp',
                   'D:\\Path\\To\\Some\\Shapefiles\\Source_File_2.shp',
                   'D:\\Path\\To\\Some\\Shapefiles\\Source_File_3.shp']

result_1 = processing.run("native:mergevectorlayers",
                {'LAYERS':sourceFiles,
                'CRS':QgsCoordinateReferenceSystem('EPSG:3857'),
                'OUTPUT':'TEMPORARY_OUTPUT'})
                
#Add temporary output layer to project to pass its source string to QgsProcessingFeatureSourceDefinition class constructor
QgsProject.instance().addMapLayer(result_1['OUTPUT'], False)

processing.run("native:dissolve",
                {'INPUT':QgsProcessingFeatureSourceDefinition(
                result_1['OUTPUT'].source(),
                selectedFeaturesOnly=False,
                featureLimit=-1,
                flags=QgsProcessingFeatureSourceDefinition.FlagOverrideDefaultGeometryCheck,
                geometryCheck=QgsFeatureRequest.GeometryNoCheck),
                'FIELD':[],
                #To create a file output pass a path and extention to output param (like below
                'OUTPUT':'D:\\Path\\To\\Directory\\Dissolve_3_Files.shp'
                })

Links to a few other relevant questions and answers for reference:

Running PyQGIS algorithm on selected features in layer

Using QGIS 3 Processing algorithms from PyQGIS standalone scripts (outside of GUI)

Layer is not valid error in my standalone PyQGIS script/app

Based on further clarification in comments, I tested running this as standalone script from the command line (with pyqgis environment properly set) and it worked fine for me using the script below (with my own paths of course).

# See https://gis.stackexchange.com/questions/279874/using-qgis-3-processing-algorithms-from-pyqgis-standalone-scripts-outside-of-gu
import sys

import os

from qgis.core import (
     QgsApplication, 
     QgsCoordinateReferenceSystem,
     QgsProject,
     QgsProcessingFeatureSourceDefinition,
     QgsFeatureRequest
)
from qgis.analysis import QgsNativeAlgorithms

# See https://gis.stackexchange.com/a/155852/4972 for details about the prefix 
QgsApplication.setPrefixPath('C:/OSGeo4W/apps/qgis', True)
qgs = QgsApplication([], False)
qgs.initQgis()

# Append the path where processing plugin can be found
sys.path.append('C:\\OSGeo4W\\apps\\qgis\\python\\plugins')

import processing
from processing.core.Processing import Processing
Processing.initialize()
QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms())

sourceFiles = ['D:\\Path\\To\\Some\\Shapefiles\\Source_File_1.shp',
                   'D:\\Path\\To\\Some\\Shapefiles\\Source_File_2.shp',
                   'D:\\Path\\To\\Some\\Shapefiles\\Source_File_3.shp']

result_1 = processing.run("native:mergevectorlayers",
                {'LAYERS':sourceFiles,
                'CRS':QgsCoordinateReferenceSystem('EPSG:3857'),
                'OUTPUT':'TEMPORARY_OUTPUT'})
                
#Add temporary output layer to project to pass its source string to QgsProcessingFeatureSourceDefinition class constructor
QgsProject.instance().addMapLayer(result_1['OUTPUT'], False)

processing.run("native:dissolve",
                {'INPUT':QgsProcessingFeatureSourceDefinition(
                result_1['OUTPUT'].source(),
                selectedFeaturesOnly=False,
                featureLimit=-1,
                flags=QgsProcessingFeatureSourceDefinition.FlagOverrideDefaultGeometryCheck,
                geometryCheck=QgsFeatureRequest.GeometryNoCheck),
                'FIELD':[],
                #To create a file output pass a path and extention to output param (like below
                'OUTPUT':'D:\\Path\\To\\Directory\\Dissolve_3_Files.shp'
                })

Links to a few other relevant questions and answers for reference:

Running PyQGIS algorithm on selected features in layer

Using QGIS 3 Processing algorithms from PyQGIS standalone scripts (outside of GUI)

Layer is not valid error in my standalone PyQGIS script/app

Source Link
Ben W
  • 23.1k
  • 3
  • 19
  • 43

Because you are using a QgsProcessingFeatureSourceDefinition class object, you need to add the intermediate temporary output layer to the project, then pass its source string to the class constructor. You can pass an argument to the addMapLayer() method so that the intermediate layer will not be added to the legend.

Also, you don't really need to use QgsVectorFileWriter, if you want a permanent file as your final processing output, just set a valid file path (including extension such as .shp or .gpkg) value to the 'OUTPUT' parameters key.

Try the script below (tested in 3.16):

def main():
    
    sourceFiles = ['D:\\Path\\To\\Some\\Shapefiles\\Source_File_1.shp',
                   'D:\\Path\\To\\Some\\Shapefiles\\Source_File_2.shp',
                   'D:\\Path\\To\\Some\\Shapefiles\\Source_File_3.shp']

    result_1 = processing.run("native:mergevectorlayers",
                    {'LAYERS':sourceFiles,
                    'CRS':QgsCoordinateReferenceSystem('EPSG:3857'),
                    'OUTPUT':'TEMPORARY_OUTPUT'})

    #Add temporary output layer to project to pass its source string to QgsProcessingFeatureSourceDefinition class constructor
    #setting the 2nd argument to False prevents the layer being added to the legend
    QgsProject.instance().addMapLayer(result_1['OUTPUT'], False)

    processing.runAndLoadResults("native:dissolve",
                    {'INPUT':QgsProcessingFeatureSourceDefinition(
                    result_1['OUTPUT'].source(),
                    selectedFeaturesOnly=False,
                    featureLimit=-1,
                    flags=QgsProcessingFeatureSourceDefinition.FlagOverrideDefaultGeometryCheck,
                    geometryCheck=QgsFeatureRequest.GeometryNoCheck),
                    'FIELD':[],
                    'OUTPUT':'TEMPORARY_OUTPUT'
                    #To create a file output pass a path and extention to output param (like below)
                    #'OUTPUT':'D:\\Path\\To\\Directory\\Dissolve_3_Files.shp'
                    })
                    
main()

On the other hand, if you don't particularly need to use QgsProcessingFeatureSourceDefinition, then you can simply pass results['OUTPUT'] directly from the first algorithm as the input to the second algorithm. E.g.

def main():

    sourceFiles = ['D:\\Path\\To\\Some\\Shapefiles\\Source_File_1.shp',
                   'D:\\Path\\To\\Some\\Shapefiles\\Source_File_2.shp',
                   'D:\\Path\\To\\Some\\Shapefiles\\Source_File_3.shp']

    result_1 = processing.run("native:mergevectorlayers",
                    {'LAYERS':sourceFiles,
                    'CRS':QgsCoordinateReferenceSystem('EPSG:3857'),
                    'OUTPUT':'TEMPORARY_OUTPUT'})
                    

    processing.runAndLoadResults("native:dissolve",
                    {'INPUT':result_1['OUTPUT'],
                    'FIELD':[],
                    'OUTPUT':'TEMPORARY_OUTPUT'
                    #To create a file output pass a path and extention to output param (like below
                    #'OUTPUT':'D:\\Path\\To\\Directory\\Dissolve_3_Files.shp'
                    })
                    
main()