3

I want to make a script which

  • processes some algorithms with multiple layers as inputs
  • outputs some results in QGIS project
  • then save the layers as zip files in a specified folder

I have not been successful yet but I have found some interesting informations with post processing methods by Ben W and Kadir Şahbaz : Adding output layers of QGIS processing scripts to group using PyQGIS / Table of content abnormally closing after using showAttributeTable (Processing plugin)

from zipfile import ZipFile

from qgis.core import QgsProcessing
from qgis.core import QgsProcessingAlgorithm
from qgis.core import QgsProcessingMultiStepFeedback
from qgis.core import QgsProcessingParameterVectorLayer
from qgis.core import QgsProcessingParameterFeatureSink
from qgis.core import QgsProcessingParameterFolderDestination
from qgis.core import QgsProcessingUtils
import processing


class MyClass(QgsProcessingAlgorithm):

# reference to the output layer id   
dest_id = {}

def initAlgorithm(self, config=None):
    self.addParameter(QgsProcessingParameterVectorLayer('path', 'path', types=[QgsProcessing.TypeVectorLine], defaultValue=None))
    self.addParameter(QgsProcessingParameterVectorLayer('point', 'point', types=[QgsProcessing.TypeVectorPoint], defaultValue=None))
    self.addParameter(QgsProcessingParameterFeatureSink('joint', 'jointure', optional=True, type=QgsProcessing.TypeVectorAnyGeometry, createByDefault=True, defaultValue=None))
    self.addParameter(QgsProcessingParameterFeatureSink('output', 'final output', type=QgsProcessing.TypeVectorAnyGeometry, createByDefault=True, supportsAppend=True, defaultValue=None))
    self.addParameter(QgsProcessingParameterFolderDestination('save', 'Save to folder :', createByDefault=True, defaultValue=None))

    
def processAlgorithm(self, parameters, context, model_feedback):
    feedback = QgsProcessingMultiStepFeedback(15, model_feedback)
    results = {}
    outputs = {}

    # lot of algorithms process

    # example of one of my ouputs/results
    outputs['RefactorSite'] = processing.run('native:refactorfields', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
    results['final output'] = outputs['RefactorSite']['OUTPUT']
    
    # pass results to post processing

    self.dest_id['One_of_my_processing_outputs'] = QgsProcessingUtils.mapLayerFromString(results['One_of_my_processing_outputs'], context)
    return results

Then I want to pass processed layers to post process to zip all of them to the specified folder

def postProcessAlgorithm(self, context, feedback):
    
    filenames = QgsProcessingUtils.mapLayerFromString(self.dest_id, context)
    
    with zipfile.ZipFile("multiple_files.zip", mode="w") as archive:
        for filename in filenames:
            archive.write(filename)
    return {}

My code does not work and throws this error:

"TypeError: QgsProcessingUtils.mapLayerFromString(): argument 1 has unexpected type 'QgsVectorLayer' " or "unexpected type 'dict' "

Here is the documentation for QgsProcessingUtils.mapLayerFromString().

What is wrong with my code?

7
  • I am facing a type error : " TypeError: QgsProcessingUtils.mapLayerFromString(): argument 1 has unexpected type 'QgsVectorLayer' " or "unexpected type 'dict' " with multiples outputs If anyone can better understand how this method works, here is the documentation qgis.org/pyqgis/3.22/core/…
    – Caligraphy
    Commented Mar 3, 2022 at 14:35
  • 1
    You probably need to save the layers to file(s) then zip the file(s). See gis.stackexchange.com/questions/354517/…
    – Bera
    Commented Mar 3, 2022 at 18:01
  • I have tried to re-use one of the output in processAlgorithm : self.final_layer['Layer_out'] = QgsProcessingUtils.mapLayerFromString(results['Layer_out'], context) with this variable on top : final_layer = {} then tried to pass to ppa : def postProcessAlgorithm(self, context, feedback): lyr = QgsProcessingUtils.mapLayerFromString(final_layer, context) but it still does an error "File "<string>", line 266, in postProcessAlgorithm NameError: name 'final_layer' is not defined"
    – Caligraphy
    Commented Mar 10, 2022 at 14:03
  • @BERA : QGIS already provide a save files algorithm but then I may require the post processing for ziping the saved files
    – Caligraphy
    Commented Mar 10, 2022 at 14:26
  • Maybe you can save them to disk (if that is needed, I dont know), zip, delete them using for example os.remove
    – Bera
    Commented Mar 10, 2022 at 14:35

1 Answer 1

1

I forgot to answer my question. I found a "decent" solution with ppa:

def postProcessAlgorithm(self, context, feedback):
    
    path = 'your path url here'
    
    for elem in self.final_layers:
        ctxt = QgsProject.instance().transformContext()      
        name = elem.name()
        url = path + name + '.geojson'
        options = QgsVectorFileWriter.SaveVectorOptions()
        options.layerName = name
        options.fileEncoding = elem.dataProvider().encoding()
        options.driverName = "geoJSON"
        QgsVectorFileWriter.writeAsVectorFormatV2(layer=elem, fileName=url, context=ctxt, options=options)
    
    # zip files
    zipname = path + 'archived ' + datetime.datetime.now().strftime('%d-%m-%Y %H-%M') + '.zip'
    directory = pathlib.Path(path)

    with zipfile.ZipFile(zipname, mode="w") as archive:
        for file_path in directory.iterdir():
            last_part = file_path.parts[-1]
            if last_part.endswith('.zip'):
                continue
            archive.write(file_path, arcname=file_path.name)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.