I have a Python application that runs some QGIS processing tools. The tools are called in a loop and I am looking to clean up the tool outputs (shapefiles) in between each iteration. I have found that only a call to qgs.exitQgis() releases the locks on the shapefile (the output of the snap process). But if I try to do further processing or try to initialize QGIS again, the Python execution stops, no exception. I have tried permutations of this but it seems any calls to QGIS or processing after qgs.exitQgis() stops the execution.
I assume it is the layer registry that has a lock on the shapefile and that exitQgis clearing of the layer registry is releasing the lock. I also suspect clearing the provider registry breaks everything else...
How can I release the lock so I can delete the intermediate files. (Some intermediate layers are inputs to OGR processes, so I don't want to create them in memory, I want to be able to open them as OGR layers).
I got this far looking at Using QGIS Processing algorithms from PyQGIS standalone scripts (outside of GUI) and other posts on StackExchange.
import os
import sys
import stat
import shutil
from osgeo import gdal #used for other things not in this sample
from qgis.core import (
QgsApplication,
QgsProcessingFeedback,
QgsVectorLayer
)
from qgis.analysis import QgsNativeAlgorithms
QgsApplication.setPrefixPath("C:\Program Files\QGIS 3.30.3\apps\qgis\bin", True)
#sys.path.append('C:/Program Files/QGIS 3.30.3/apps/qgis/python/plugins') #this is handled in a shell or batch script calling this py
import processing
from processing.core.Processing import Processing
def delFolder(folder):
def on_rm_error(_action, path, _exc):
os.chmod(path, stat.S_IWRITE)
os.remove(path)
if os.path.exists(folder) and os.path.isdir(folder):
shutil.rmtree(folder, onerror=on_rm_error)
print(f'removed directory {folder}')
def main():
try:
qgs = QgsApplication([], False)
qgs.initQgis()
Processing.initialize()
inputlayer =r'C:/temp/temp/inputPoly.shp'
outputPath = r'C:/temp/temp/tmp'
snaplayer=r'C:/temp/temp/tmp/polysnap.shp'
dissolvelayer=r'C:/temp/temp/tmp/polydiss.shp'
os.makedirs(outputPath, exist_ok = True)
print("snap")
processing.run("native:snapgeometries", {'INPUT':inputlayer,'REFERENCE_LAYER':inputlayer,'TOLERANCE':1,'BEHAVIOR':0,'OUTPUT':snaplayer})
print('snapped')
print('dissolve')
processing.run("native:dissolve", {'INPUT':snaplayer,'FIELD':['POLY_TYPE'],'SEPARATE_DISJOINT':True,'OUTPUT':dissolvelayer})
print('dissolved')
Processing.deinitialize() #tried with and without this
qgs.exitQgis() #releases the snap lock, the dissolved shapefile doesn't seem locked at all
#qgs.exit() #doesn't seem to make a difference for the lock
print(f'try to delete temp folder {outputPath}')
delFolder(outputPath)
#do the same processing for the sake of the test
os.makedirs(outputPath, exist_ok = True)
print(f"{outputPath} made")
qgs.initQgis() #script ends here, tried creating a new qgs but I think it is singleton
print('qgsApp initialized')
Processing.initialize() #tried with and without
print('processing initialized')
#do again for test
print("snap")
processing.run("native:snapgeometries", {'INPUT':inputlayer,'REFERENCE_LAYER':inputlayer,'TOLERANCE':1,'BEHAVIOR':0,'OUTPUT':snaplayer})
print('snapped')
print('dissolve')
processing.run("native:dissolve", {'INPUT':snaplayer,'FIELD':['POLY_TYPE'],'SEPARATE_DISJOINT':True,'OUTPUT':dissolvelayer})
print('dissolved')
Processing.deinitialize()
qgs.exitQgis()
qgs.exit()
print(f'try to delete temp folder {outputPath}')
delFolder(outputPath)
except Exception as e:
print(e)
if __name__ == "__main__":
main()