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?

DannaC17
  • 75
  • 6
Caligraphy
  • 139
  • 11
  • 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 https://qgis.org/pyqgis/3.22/core/QgsProcessingUtils.html?#qgis.core.QgsProcessingUtils.mapLayerFromString

    – Caligraphy Mar 03 '22 at 14:35
  • 1
    You probably need to save the layers to file(s) then zip the file(s). See https://gis.stackexchange.com/questions/354517/save-qgsvectorlayer-to-file – BERA Mar 03 '22 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 "", line 266, in postProcessAlgorithm NameError: name 'final_layer' is not defined"

    – Caligraphy Mar 10 '22 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 Mar 10 '22 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 Mar 10 '22 at 14:35
  • Can you provide a minimal working example producing the issue? – Kadir Şahbaz Mar 10 '22 at 14:57
  • @Kadir Şahbaz

    https://trinket.io/python/c13efba0d6

    – Caligraphy Mar 11 '22 at 09:42

1 Answers1

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)

Caligraphy
  • 139
  • 11