def _alg_tester(self, alg_name, input_layer, parameters): alg = self.registry.createAlgorithmById(alg_name) self.assertIsNotNone(alg) parameters['INPUT'] = input_layer parameters['OUTPUT'] = 'memory:' old_features = [f for f in input_layer.getFeatures()] input_layer.selectByIds([old_features[0].id()]) # Check selected self.assertEqual(input_layer.selectedFeatureIds(), [old_features[0].id()], alg_name) context = QgsProcessingContext() context.setProject(QgsProject.instance()) feedback = ConsoleFeedBack() input_layer.rollBack() ok = False ok, _ = execute_in_place_run( alg, parameters, context=context, feedback=feedback, raise_exceptions=True) new_features = [f for f in input_layer.getFeatures()] # Check ret values self.assertTrue(ok, alg_name) # Check geometry types (drop Z or M) self.assertEqual(new_features[0].geometry().wkbType(), old_features[0].geometry().wkbType()) return old_features, new_features
def testRun(self): context = QgsProcessingContext() # try running an alg using processing.run - ownership of result layer should be transferred back to the caller res = processing.run('qgis:buffer', {'DISTANCE': 1, 'INPUT': points(), 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT}, context=context) self.assertIn('OUTPUT', res) # output should be the layer instance itself self.assertIsInstance(res['OUTPUT'], QgsVectorLayer) # Python should have ownership self.assertTrue(sip.ispyowned(res['OUTPUT'])) del context gc.collect() self.assertFalse(sip.isdeleted(res['OUTPUT'])) # now try using processing.run with is_child_algorithm = True. Ownership should remain with the context context = QgsProcessingContext() res = processing.run('qgis:buffer', {'DISTANCE': 1, 'INPUT': points(), 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT}, context=context, is_child_algorithm=True) self.assertIn('OUTPUT', res) # output should be a layer string reference, NOT the layer itself self.assertIsInstance(res['OUTPUT'], str) layer = context.temporaryLayerStore().mapLayer(res['OUTPUT']) self.assertIsInstance(layer, QgsVectorLayer) # context should have ownership self.assertFalse(sip.ispyowned(layer)) del context gc.collect() self.assertTrue(sip.isdeleted(layer))
def testGdalScripts(self): '''Test GDAL scripts2''' layer = QgsRasterLayer(os.path.join(os.path.dirname(__file__), "data","dem25.tif"), "dem") QgsProject.instance().addMapLayer(layer) context = QgsProcessingContext() context.setProject(QgsProject.instance()) alg = QgsApplication.processingRegistry().createAlgorithmById('gdal:rastercalculator') self.assertIsNotNone(alg) parameters = {'INPUT_A':'dem', 'BAND_A':1,'INPUT_B':None,'BAND_B':-1, 'INPUT_C':None,'BAND_C':-1,'INPUT_D':None, 'BAND_D':-1,'INPUT_E':None,'BAND_E':-1, 'INPUT_F':None,'BAND_F':-1,'FORMULA':'A*2', 'NO_DATA':None,'RTYPE':5,'OPTIONS':'', 'OUTPUT':'TEMPORARY_OUTPUT'} feedback = QgsProcessingFeedback() results, ok = alg.run(parameters, context, feedback) self.assertTrue(ok) self.assertTrue(os.path.exists(results["OUTPUT"])) QgsProject.instance().removeMapLayer(layer)
def test_select_all_features(self): """Check that if there is no selection, the alg will run on all features""" self.vl.rollBack() self.vl.removeSelection() old_count = self.vl.featureCount() context = QgsProcessingContext() context.setProject(QgsProject.instance()) feedback = ConsoleFeedBack() alg = self.registry.createAlgorithmById('native:translategeometry') self.assertIsNotNone(alg) parameters = { 'DELTA_X': 1.1, 'DELTA_Y': 1.1, } parameters['INPUT'] = self.vl parameters['OUTPUT'] = 'memory:' old_features = [f for f in self.vl.getFeatures()] ok, _ = execute_in_place_run( alg, parameters, context=context, feedback=feedback, raise_exceptions=True) new_features = [f for f in self.vl.getFeatures()] self.assertEqual(len(new_features), old_count) # Check all are selected self.assertEqual(len(self.vl.selectedFeatureIds()), old_count)
def test_parameterAs_ScriptMode(self): """ This test will pass an instance of QgsCoordinateReferenceSystem for 'epsg' parameter of otb::Rasterization. There is same test in otb_algorithm_tests.yaml which passes an instance of str for epsg parameter. """ outdir = tempfile.mkdtemp() self.cleanup_paths.append(outdir) context = QgsProcessingContext() context.setProject(QgsProject.instance()) feedback = QgsProcessingFeedback() vectorFile = os.path.join(AlgorithmsTestBase.processingTestDataPath(), 'polys.gml') vectorLayer = QgsProcessingUtils.mapLayerFromString(vectorFile, context) parameters = { 'in': vectorLayer, 'epsg': QgsCoordinateReferenceSystem('EPSG:4326'), 'spx': 1.0, 'spy': 1.0, 'outputpixeltype': 1, 'out': os.path.join(outdir, 'raster.tif') } results = processing.run('otb:Rasterization', parameters, None, feedback) result_lyr = QgsProcessingUtils.mapLayerFromString(results['out'], context) self.assertTrue(result_lyr.isValid())
def test_check_validity(self): """Test that the output invalid contains the error reason""" polygon_layer = self._make_layer('Polygon') self.assertTrue(polygon_layer.startEditing()) f = QgsFeature(polygon_layer.fields()) f.setAttributes([1]) # Flake! f.setGeometry(QgsGeometry.fromWkt( 'POLYGON ((0 0, 2 2, 0 2, 2 0, 0 0))')) self.assertTrue(f.isValid()) f2 = QgsFeature(polygon_layer.fields()) f2.setAttributes([1]) f2.setGeometry(QgsGeometry.fromWkt( 'POLYGON((1.1 1.1, 1.1 2.1, 2.1 2.1, 2.1 1.1, 1.1 1.1))')) self.assertTrue(f2.isValid()) self.assertTrue(polygon_layer.addFeatures([f, f2])) polygon_layer.commitChanges() polygon_layer.rollBack() self.assertEqual(polygon_layer.featureCount(), 2) QgsProject.instance().addMapLayers([polygon_layer]) alg = self.registry.createAlgorithmById('qgis:checkvalidity') context = QgsProcessingContext() context.setProject(QgsProject.instance()) feedback = ConsoleFeedBack() self.assertIsNotNone(alg) parameters = {} parameters['INPUT_LAYER'] = polygon_layer.id() parameters['VALID_OUTPUT'] = 'memory:' parameters['INVALID_OUTPUT'] = 'memory:' parameters['ERROR_OUTPUT'] = 'memory:' # QGIS method parameters['METHOD'] = 1 ok, results = execute( alg, parameters, context=context, feedback=feedback) self.assertTrue(ok) invalid_layer = QgsProcessingUtils.mapLayerFromString( results['INVALID_OUTPUT'], context) self.assertEqual(invalid_layer.fields().names()[-1], '_errors') self.assertEqual(invalid_layer.featureCount(), 1) f = next(invalid_layer.getFeatures()) self.assertEqual(f.attributes(), [ 1, 'segments 0 and 2 of line 0 intersect at 1, 1']) # GEOS method parameters['METHOD'] = 2 ok, results = execute( alg, parameters, context=context, feedback=feedback) self.assertTrue(ok) invalid_layer = QgsProcessingUtils.mapLayerFromString( results['INVALID_OUTPUT'], context) self.assertEqual(invalid_layer.fields().names()[-1], '_errors') self.assertEqual(invalid_layer.featureCount(), 1) f = next(invalid_layer.getFeatures()) self.assertEqual(f.attributes(), [1, 'Self-intersection'])
def testFeatureSourceInput(self): # create a memory layer and add to project and context layer = QgsVectorLayer("Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer", "testmem", "memory") self.assertTrue(layer.isValid()) pr = layer.dataProvider() f = QgsFeature() f.setAttributes(["test", 123]) f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(100, 200))) f2 = QgsFeature() f2.setAttributes(["test2", 457]) f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(110, 200))) self.assertTrue(pr.addFeatures([f, f2])) self.assertEqual(layer.featureCount(), 2) # select first feature layer.selectByIds([next(layer.getFeatures()).id()]) self.assertEqual(len(layer.selectedFeatureIds()), 1) QgsProject.instance().addMapLayer(layer) context = QgsProcessingContext() context.setProject(QgsProject.instance()) alg = QgsApplication.processingRegistry().createAlgorithmById('grass7:v.buffer') self.assertIsNotNone(alg) temp_file = os.path.join(self.temp_dir, 'grass_output_sel.shp') parameters = {'input': QgsProcessingFeatureSourceDefinition('testmem', True), 'cats': '', 'where': '', 'type': [0, 1, 4], 'distance': 1, 'minordistance': None, 'angle': 0, 'column': None, 'scale': 1, 'tolerance': 0.01, '-s': False, '-c': False, '-t': False, 'output': temp_file, 'GRASS_REGION_PARAMETER': None, 'GRASS_SNAP_TOLERANCE_PARAMETER': -1, 'GRASS_MIN_AREA_PARAMETER': 0.0001, 'GRASS_OUTPUT_TYPE_PARAMETER': 0, 'GRASS_VECTOR_DSCO': '', 'GRASS_VECTOR_LCO': ''} feedback = QgsProcessingFeedback() results, ok = alg.run(parameters, context, feedback) self.assertTrue(ok) self.assertTrue(os.path.exists(temp_file)) # make sure that layer has correct features res = QgsVectorLayer(temp_file, 'res') self.assertTrue(res.isValid()) self.assertEqual(res.featureCount(), 1) QgsProject.instance().removeMapLayer(layer)
def check_algorithm(self, name, defs): """ Will run an algorithm definition and check if it generates the expected result :param name: The identifier name used in the test output heading :param defs: A python dict containing a test algorithm definition """ self.vector_layer_params = {} QgsProject.instance().removeAllMapLayers() params = self.load_params(defs['params']) print('Running alg: "{}"'.format(defs['algorithm'])) alg = QgsApplication.processingRegistry().createAlgorithmById(defs['algorithm']) parameters = {} if isinstance(params, list): for param in zip(alg.parameterDefinitions(), params): parameters[param[0].name()] = param[1] else: for k, p in list(params.items()): parameters[k] = p for r, p in list(defs['results'].items()): if not 'in_place_result' in p or not p['in_place_result']: parameters[r] = self.load_result_param(p) expectFailure = False if 'expectedFailure' in defs: exec(('\n'.join(defs['expectedFailure'][:-1])), globals(), locals()) expectFailure = eval(defs['expectedFailure'][-1]) # ignore user setting for invalid geometry handling context = QgsProcessingContext() context.setProject(QgsProject.instance()) if 'skipInvalid' in defs and defs['skipInvalid']: context.setInvalidGeometryCheck(QgsFeatureRequest.GeometrySkipInvalid) feedback = QgsProcessingFeedback() print('Algorithm parameters are {}'.format(parameters)) # first check that algorithm accepts the parameters we pass... ok, msg = alg.checkParameterValues(parameters, context) self.assertTrue(ok, 'Algorithm failed checkParameterValues with result {}'.format(msg)) if expectFailure: try: results, ok = alg.run(parameters, context, feedback) self.check_results(results, context, parameters, defs['results']) if ok: raise _UnexpectedSuccess except Exception: pass else: results, ok = alg.run(parameters, context, feedback) self.assertTrue(ok, 'params: {}, results: {}'.format(parameters, results)) self.check_results(results, context, parameters, defs['results'])
def test_bad_script_dont_crash(self): # spellok """Test regression #21270 (segfault)""" context = QgsProcessingContext() context.setProject(QgsProject.instance()) feedback = ConsoleFeedBack() task = QgsProcessingAlgRunnerTask(CrashingProcessingAlgorithm(), {}, context=context, feedback=feedback) self.assertTrue(task.isCanceled()) self.assertIn('name \'ExampleProcessingAlgorithm\' is not defined', feedback._error)
def check_algorithm(self, name, defs): """ Will run an algorithm definition and check if it generates the expected result :param name: The identifier name used in the test output heading :param defs: A python dict containing a test algorithm definition """ self.vector_layer_params = {} QgsProject.instance().removeAllMapLayers() params = self.load_params(defs['params']) if defs['algorithm'].startswith('script:'): filePath = os.path.join(processingTestDataPath(), 'scripts', '{}.py'.format(defs['algorithm'][len('script:'):])) alg = ScriptAlgorithm(filePath) alg.initAlgorithm() else: alg = QgsApplication.processingRegistry().createAlgorithmById(defs['algorithm']) parameters = {} if isinstance(params, list): for param in zip(alg.parameterDefinitions(), params): parameters[param[0].name()] = param[1] else: for k, p in list(params.items()): parameters[k] = p for r, p in list(defs['results'].items()): if not 'in_place_result' in p or not p['in_place_result']: parameters[r] = self.load_result_param(p) expectFailure = False if 'expectedFailure' in defs: exec(('\n'.join(defs['expectedFailure'][:-1])), globals(), locals()) expectFailure = eval(defs['expectedFailure'][-1]) # ignore user setting for invalid geometry handling context = QgsProcessingContext() context.setProject(QgsProject.instance()) feedback = QgsProcessingFeedback() if expectFailure: try: results, ok = alg.run(parameters, context, feedback) self.check_results(results, context, defs['params'], defs['results']) if ok: raise _UnexpectedSuccess except Exception: pass else: results, ok = alg.run(parameters, context, feedback) self.assertTrue(ok, 'params: {}, results: {}'.format(parameters, results)) self.check_results(results, context, defs['params'], defs['results'])
def test_bug21373_mode_raster(self): """ This issue is reported on qgis bug tracker: #21373 """ context = QgsProcessingContext() context.setProject(QgsProject.instance()) feedback = QgsProcessingFeedback() parameters = { 'in': TestOtbAlgorithms.__input_raster_layer(), 'filter': 'meanshift', 'mode': 'raster', 'mode.raster.out': 'raster.tif' } alg = OtbAlgorithm('Segmentation', 'Segmentation', os.path.join(self.descrFolder, 'Segmentation.txt')) results = alg.processAlgorithm(parameters, context, feedback) self.assertDictEqual(results, {'mode.raster.out': 'raster.tif'})
def test_bug21374_Fail(self): """ This issue is reported on qgis bug tracker: #21374 """ outdir = tempfile.mkdtemp() self.cleanup_paths.append(outdir) context = QgsProcessingContext() context.setProject(QgsProject.instance()) feedback = QgsProcessingFeedback() parameters = { 'in': TestOtbAlgorithms.__input_raster_layer(), 'filter': 'cc', 'mode.vector.out': os.path.join(outdir, 'vector.shp') } alg = OtbAlgorithm('Segmentation', 'Segmentation', os.path.join(self.descrFolder, 'Segmentation.txt')) ok, msg = alg.checkParameterValues(parameters, context) self.assertFalse(ok, 'Algorithm failed checkParameterValues with result {}'.format(msg))
def testRunAndLoadResults(self): QgsProject.instance().removeAllMapLayers() context = QgsProcessingContext() # try running an alg using processing.runAndLoadResults - ownership of result layer should be transferred to # project, and layer should be present in project res = processing.runAndLoadResults('qgis:buffer', {'DISTANCE': 1, 'INPUT': points(), 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT}, context=context) self.assertIn('OUTPUT', res) # output should be the layer path self.assertIsInstance(res['OUTPUT'], str) self.assertEqual(context.layersToLoadOnCompletion()[res['OUTPUT']].project, QgsProject.instance()) layer = QgsProject.instance().mapLayer(res['OUTPUT']) self.assertIsInstance(layer, QgsVectorLayer) # Python should NOT have ownership self.assertFalse(sip.ispyowned(layer))
def _make_compatible_tester(self, feature_wkt, layer_wkb_name, attrs=[1]): layer = self._make_layer(layer_wkb_name) layer.startEditing() f = QgsFeature(layer.fields()) f.setAttributes(attrs) f.setGeometry(QgsGeometry.fromWkt(feature_wkt)) self.assertTrue(f.isValid()) context = QgsProcessingContext() context.setProject(QgsProject.instance()) # Fix it! new_features = make_features_compatible([f], layer) for new_f in new_features: self.assertEqual(new_f.geometry().wkbType(), layer.wkbType()) self.assertTrue(layer.addFeatures(new_features), "Fail: %s - %s - %s" % (feature_wkt, attrs, layer_wkb_name)) return layer, new_features
def test_non_ascii_output(self): # create a memory layer and add to project and context layer = QgsVectorLayer("Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer", "testmem", "memory") self.assertTrue(layer.isValid()) pr = layer.dataProvider() f = QgsFeature() f.setAttributes(["test", 123]) f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(100, 200))) f2 = QgsFeature() f2.setAttributes(["test2", 457]) f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(110, 200))) self.assertTrue(pr.addFeatures([f, f2])) self.assertEqual(layer.featureCount(), 2) QgsProject.instance().addMapLayer(layer) context = QgsProcessingContext() context.setProject(QgsProject.instance()) alg = QgsApplication.processingRegistry().createAlgorithmById('saga:fixeddistancebuffer') self.assertIsNotNone(alg) temp_file = os.path.join(self.temp_dir, 'non_ascii_ñññ.shp') parameters = {'SHAPES': 'testmem', 'DIST_FIELD_DEFAULT': 5, 'NZONES': 1, 'DARC': 5, 'DISSOLVE': False, 'POLY_INNER': False, 'BUFFER': temp_file} feedback = QgsProcessingFeedback() results, ok = alg.run(parameters, context, feedback) self.assertTrue(ok) self.assertTrue(os.path.exists(temp_file)) # make sure that layer has correct features res = QgsVectorLayer(temp_file, 'res') self.assertTrue(res.isValid()) self.assertEqual(res.featureCount(), 2) QgsProject.instance().removeMapLayer(layer)
def createBaseMapLayer(self, map_theme, layer, tile_size, map_units_per_pixel): """ Create a basemap from map layer(s) :param dataPath: The path where the basemap should be writtent to :param extent: The extent rectangle in which data shall be fetched :param map_theme: The name of the map theme to be rendered :param layer: A layer id to be rendered. Will only be used if map_theme is None. :param tile_size: The extent rectangle in which data shall be fetched :param map_units_per_pixel: Number of map units per pixel (1: 1 m per pixel, 10: 10 m per pixel...) """ extent_string = '{},{},{},{}'.format(self.extent.xMinimum(), self.extent.xMaximum(), self.extent.yMinimum(), self.extent.yMaximum()) alg = QgsApplication.instance().processingRegistry().createAlgorithmById('qgis:rasterize') params = { 'EXTENT': extent_string, 'MAP_THEME': map_theme, 'LAYER': layer, 'MAP_UNITS_PER_PIXEL': map_units_per_pixel, 'TILE_SIZE': tile_size, 'MAKE_BACKGROUND_TRANSPARENT': False, 'OUTPUT': os.path.join(self.export_folder, 'basemap.gpkg') } feedback = QgsProcessingFeedback() context = QgsProcessingContext() context.setProject(QgsProject.instance()) results, ok = alg.run(params, context, feedback) new_layer = QgsRasterLayer(results['OUTPUT'], self.tr('Basemap')) resample_filter = new_layer.resampleFilter() resample_filter.setZoomedInResampler(QgsCubicRasterResampler()) resample_filter.setZoomedOutResampler(QgsBilinearRasterResampler()) self.project_configuration.project.addMapLayer(new_layer, False) layer_tree = QgsProject.instance().layerTreeRoot() layer_tree.insertLayer(len(layer_tree.children()), new_layer)
def testGetOgrCompatibleSourceFromFeatureSource(self): # create a memory layer and add to project and context layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", "testmem", "memory") self.assertTrue(layer.isValid()) pr = layer.dataProvider() f = QgsFeature() f.setAttributes(["test", 123]) f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(100, 200))) f2 = QgsFeature() f2.setAttributes(["test2", 457]) f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(100, 200))) self.assertTrue(pr.addFeatures([f, f2])) self.assertEqual(layer.featureCount(), 2) # select first feature layer.selectByIds([next(layer.getFeatures()).id()]) self.assertEqual(len(layer.selectedFeatureIds()), 1) QgsProject.instance().addMapLayer(layer) context = QgsProcessingContext() context.setProject(QgsProject.instance()) alg = QgsApplication.processingRegistry().createAlgorithmById('gdal:buffervectors') self.assertIsNotNone(alg) parameters = {'INPUT': QgsProcessingFeatureSourceDefinition('testmem', True)} feedback = QgsProcessingFeedback() # check that memory layer is automatically saved out to shape when required by GDAL algorithms ogr_data_path, ogr_layer_name = alg.getOgrCompatibleSource('INPUT', parameters, context, feedback, executing=True) self.assertTrue(ogr_data_path) self.assertTrue(ogr_data_path.endswith('.shp')) self.assertTrue(os.path.exists(ogr_data_path)) self.assertTrue(ogr_layer_name) # make sure that layer has only selected feature res = QgsVectorLayer(ogr_data_path, 'res') self.assertTrue(res.isValid()) self.assertEqual(res.featureCount(), 1) QgsProject.instance().removeMapLayer(layer)
def processAlgorithm(self, parameters, context, feedback): connection = self.parameterAsString(parameters, self.DATABASE, context) id_field = self.parameterAsString(parameters, self.ID_FIELD, context) geom_field = self.parameterAsString(parameters, self.GEOMETRY_FIELD, context) uri = postgis.uri_from_name(connection) sql = self.parameterAsString(parameters, self.SQL, context) sql = sql.replace('\n', ' ') uri.setDataSource("", "(" + sql + ")", geom_field, "", id_field) vlayer = QgsVectorLayer(uri.uri(), "layername", "postgres") if not vlayer.isValid(): raise QgsProcessingException( self.tr("""This layer is invalid! Please check the PostGIS log for error messages.""")) context.temporaryLayerStore().addMapLayer(vlayer) context.addLayerToLoadOnCompletion( vlayer.id(), QgsProcessingContext.LayerDetails('SQL layer', context.project(), self.OUTPUT)) return {self.OUTPUT: vlayer.id()}
def test_getConnectionString(self): obj = Ogr2OgrToPostGis() obj.initAlgorithm({}) parameters = {} context = QgsProcessingContext() # NOTE: defaults are debatable, see # https://github.com/qgis/QGIS/pull/3607#issuecomment-253971020 self.assertEqual(obj.getConnectionString(parameters, context), "host=localhost port=5432 active_schema=public") parameters['HOST'] = 'remote' self.assertEqual(obj.getConnectionString(parameters, context), "host=remote port=5432 active_schema=public") parameters['HOST'] = '' self.assertEqual(obj.getConnectionString(parameters, context), "port=5432 active_schema=public") parameters['PORT'] = '5555' self.assertEqual(obj.getConnectionString(parameters, context), "port=5555 active_schema=public") parameters['PORT'] = '' self.assertEqual(obj.getConnectionString(parameters, context), "active_schema=public") parameters['USER'] = '******' self.assertEqual(obj.getConnectionString(parameters, context), "active_schema=public user=usr") parameters['PASSWORD'] = '******' self.assertEqual(obj.getConnectionString(parameters, context), "password=pwd active_schema=public user=usr")
def _alg_tester(self, alg_name, input_layer, parameters, invalid_geometry_policy=QgsFeatureRequest.GeometryNoCheck, retain_selection=False): alg = self.registry.createAlgorithmById(alg_name) self.assertIsNotNone(alg) parameters['INPUT'] = input_layer parameters['OUTPUT'] = 'memory:' old_features = [f for f in input_layer.getFeatures()] if not retain_selection: input_layer.selectByIds([old_features[0].id()]) # Check selected self.assertEqual(input_layer.selectedFeatureIds(), [old_features[0].id()], alg_name) context = QgsProcessingContext() context.setInvalidGeometryCheck(invalid_geometry_policy) context.setProject(QgsProject.instance()) feedback = ConsoleFeedBack() input_layer.rollBack() ok = False ok, _ = execute_in_place_run(alg, parameters, context=context, feedback=feedback, raise_exceptions=True) new_features = [f for f in input_layer.getFeatures()] # Check ret values self.assertTrue(ok, alg_name) # Check geometry types (drop Z or M) self.assertEqual(new_features[0].geometry().wkbType(), old_features[0].geometry().wkbType()) return old_features, new_features
def testValues(self): context = QgsProcessingContext() # disable check for geometry validity context.setFlags(QgsProcessingContext.Flags(0)) test_data = points() test_layer = QgsVectorLayer(test_data, 'test', 'ogr') # field by index res = vector.values(test_layer, context, 1) self.assertEqual(res[1], [1, 2, 3, 4, 5, 6, 7, 8, 9]) # field by name res = vector.values(test_layer, context, 'id') self.assertEqual(res['id'], [1, 2, 3, 4, 5, 6, 7, 8, 9]) # two fields res = vector.values(test_layer, context, 1, 2) self.assertEqual(res[1], [1, 2, 3, 4, 5, 6, 7, 8, 9]) self.assertEqual(res[2], [2, 1, 0, 2, 1, 0, 0, 0, 0]) # two fields by name res = vector.values(test_layer, context, 'id', 'id2') self.assertEqual(res['id'], [1, 2, 3, 4, 5, 6, 7, 8, 9]) self.assertEqual(res['id2'], [2, 1, 0, 2, 1, 0, 0, 0, 0]) # two fields by name and index res = vector.values(test_layer, context, 'id', 2) self.assertEqual(res['id'], [1, 2, 3, 4, 5, 6, 7, 8, 9]) self.assertEqual(res[2], [2, 1, 0, 2, 1, 0, 0, 0, 0]) # test with selected features context.setFlags(QgsProcessingContext.UseSelectionIfPresent) test_layer.selectByIds([2, 4, 6]) res = vector.values(test_layer, context, 1) self.assertEqual(set(res[1]), set([5, 7, 3]))
def processAlgorithm(self, parameters, context, feedback): destination = self.parameterAsFile(parameters, self.DESTINATION, context) try: db = postgis.GeoDB.from_name(destination) is_geopackage = False schema = self.parameterAsFile(parameters, self.SCHEMA, context) except QgsProcessingException: is_geopackage = True schema = None if is_geopackage: if not destination.lower().endswith('.gpkg'): destination += '.gpkg' uri = destination else: database_uri = db.uri info = database_uri.connectionInfo(True) conn = psycopg2.connect(info) cur = conn.cursor() sql = "DROP VIEW IF EXISTS {}.{};".format(schema, self.VIEW_NAME) feedback.pushInfo(sql) cur.execute(sql) conn.commit() crs = self.parameterAsCrs(parameters, self.CRS, context) options = dict() options['update'] = True if is_geopackage: options['layerOptions'] = ['FID=id'] options['fileEncoding'] = 'UTF-8' output_layers = [] for table, geom in MAPPING.items(): # create virtual layer if geom[0]: vl_path = '{}?crs={}&'.format(geom[0], crs.authid()) else: vl_path = 'None?' csv_path = resources_path('data_models', '{}.csv'.format(table)) csv = QgsVectorLayer(csv_path, table, 'ogr') if not csv.isValid(): csv_path = resources_path('data_models', '{}.csv'.format(table)) raise QgsProcessingException( tr('* ERROR: Can\'t load CSV {}').format(csv_path)) fields = [] for c_f in csv.getFeatures(): fields.append('field={}:{}'.format(c_f['name'], c_f['typeName'])) del csv vl_path += '&'.join(fields) LOGGER.debug('Memory layer "{}" created with {}'.format( table, vl_path)) vl = QgsVectorLayer(vl_path, table, 'memory') if vl.fields().count() != len(fields): raise QgsProcessingException( tr('* ERROR while creating fields in layer "{}"').format( table)) # export layer options['layerName'] = vl.name() if not is_geopackage: uri = QgsDataSourceUri(database_uri) if Qgis.QGIS_VERSION_INT >= 31000: uri.setTable(vl.name()) if vl.isSpatial(): uri.setGeometryColumn('geom') else: uri_string = uri.uri(True) if vl.isSpatial(): uri_string = uri_string.replace( 'table=""', 'table="{}" (geom)'.format(vl.name())) else: uri_string = uri_string.replace( 'table=""', 'table="{}"'.format(vl.name())) uri = QgsDataSourceUri(uri_string) # Schema is updating the table name, # so after search&replace uri.setSchema(schema) uri.setKeyColumn(vl.fields().at(0).name()) exporter = QgsVectorLayerExporter( uri if is_geopackage else uri.uri(), 'ogr' if is_geopackage else 'postgres', vl.fields(), vl.wkbType(), vl.crs(), True, options) # result if exporter.errorCode() != QgsVectorLayerExporter.NoError: source = uri if is_geopackage else uri.uri() raise QgsProcessingException( tr('* ERROR while exporting the layer to "{}":"{}"'). format(source, exporter.errorMessage())) # Do create sequence if geom[2] and not is_geopackage: cur = conn.cursor() sql = "CREATE SEQUENCE {}.{}_{}_seq;".format( schema, table, geom[2]) cur.execute(sql) conn.commit() sql = ("ALTER TABLE {0}.{1} " "ALTER COLUMN {2} " "SET DEFAULT nextval('{0}.{1}_{2}_seq'::regclass);" ).format(schema, table, geom[2]) cur.execute(sql) conn.commit() # connection troncon_rereau_classif in geopackage if is_geopackage: dest_layer = QgsVectorLayer( '{}|layername={}'.format(uri, table), table, 'ogr') else: uri = QgsDataSourceUri(database_uri) if Qgis.QGIS_VERSION_INT >= 31000: uri.setTable(vl.name()) if vl.isSpatial(): uri.setGeometryColumn('geom') else: uri_string = uri.uri(True) if vl.isSpatial(): uri_string = uri_string.replace( 'table=""', 'table="{}" (geom)'.format(vl.name())) else: uri_string = uri_string.replace( 'table=""', 'table="{}"'.format(vl.name())) uri = QgsDataSourceUri(uri_string) # Schema is updating the table name, # so after search&replace uri.setSchema(schema) uri.setKeyColumn(vl.fields().at(0).name()) dest_layer = QgsVectorLayer(uri.uri(False), table, 'postgres') if not dest_layer.isValid(): source = uri if is_geopackage else uri.uri() raise QgsProcessingException( tr('* ERROR: Can\'t load table "{}" in URI "{}"').format( table, source)) feedback.pushInfo('The layer {} has been created'.format(table)) output_layers.append(dest_layer.id()) # Add layer to project context.temporaryLayerStore().addMapLayer(dest_layer) context.addLayerToLoadOnCompletion( dest_layer.id(), QgsProcessingContext.LayerDetails(table, context.project(), self.OUTPUT_LAYERS)) # Get connection if is_geopackage: conn = spatialite_connect(uri) # Do create view cur = conn.cursor() prefix = '' view_destination = self.VIEW_NAME if not is_geopackage: prefix = '{}.'.format(schema) view_destination = '{}{}'.format(prefix, view_destination) sql = ("CREATE VIEW {0} AS " "SELECT r.id, r.caa, r.id_geom_regard, r.id_file, g.geom " "FROM {1}regard r, {1}geom_regard g " "WHERE r.id_geom_regard = g.id;").format( view_destination, prefix) feedback.pushInfo(sql) cur.execute(sql) conn.commit() if is_geopackage: sql = ("INSERT INTO gpkg_contents " "(table_name, identifier, data_type, srs_id) " "VALUES ( '{0}', '{0}', 'features', {1});").format( self.VIEW_NAME, crs.postgisSrid()) feedback.pushInfo(sql) cur.execute(sql) conn.commit() sql = ( "INSERT INTO gpkg_geometry_columns " "(table_name, column_name, geometry_type_name, srs_id, z, m) " "VALUES ('{0}', 'geom', 'POINT', {1}, 0, 0);").format( self.VIEW_NAME, crs.postgisSrid()) feedback.pushInfo(sql) cur.execute(sql) conn.commit() conn.close() # Connexion à la couche view_regard_localized dans le Geopackage if is_geopackage: view_layer = QgsVectorLayer( '{}|layername={}'.format(uri, self.VIEW_NAME), self.VIEW_NAME, 'ogr') else: uri = QgsDataSourceUri(database_uri) if Qgis.QGIS_VERSION_INT >= 31000: uri.setTable(self.VIEW_NAME) uri.setGeometryColumn('geom') else: uri_string = uri.uri(True) uri_string = uri_string.replace( 'table=""', 'table="{}" (geom)'.format(self.VIEW_NAME)) uri = QgsDataSourceUri(uri_string) # Schema is updating the table name, # so after search&replace uri.setSchema(schema) uri.setKeyColumn('id') view_layer = QgsVectorLayer(uri.uri(False), self.VIEW_NAME, 'postgres') if not view_layer.isValid(): source = uri if is_geopackage else uri.uri() raise QgsProcessingException( tr('* ERROR: Can\'t load layer {} in {}').format( self.VIEW_NAME, source)) output_layers.append(view_layer.id()) # Add layer to project context.temporaryLayerStore().addMapLayer(view_layer) context.addLayerToLoadOnCompletion( view_layer.id(), QgsProcessingContext.LayerDetails(self.VIEW_NAME, context.project(), self.OUTPUT_LAYERS)) feedback.pushInfo('The data model has been created in {}'.format(uri)) return {self.DESTINATION: uri, self.OUTPUT_LAYERS: output_layers}
def createContext(feedback=None): """ Creates a default processing context """ context = QgsProcessingContext() context.setProject(QgsProject.instance()) context.setFeedback(feedback) invalid_features_method = ProcessingConfig.getSetting(ProcessingConfig.FILTER_INVALID_GEOMETRIES) if invalid_features_method is None: invalid_features_method = QgsFeatureRequest.GeometryAbortOnInvalid context.setInvalidGeometryCheck(invalid_features_method) settings = QgsSettings() context.setDefaultEncoding(settings.value("/Processing/encoding", "System")) context.setExpressionContext(createExpressionContext()) return context
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ source = self.parameterAsVectorLayer(parameters, self.INPUT, context) field_insee = self.parameterAsString(parameters, self.INSEE_CODE, context) field_commune = self.parameterAsString(parameters, self.COMMUNE_NAME, context) value_epsg = self.parameterAsString(parameters, self.EPSG_CODE, context) if value_epsg == '2154' or value_epsg == '3942' or value_epsg == '3943' or value_epsg == '3944' or value_epsg == '3945' or value_epsg == '3946' or value_epsg == '3947' or value_epsg == '3948' or value_epsg == '3949' or value_epsg == '3950' or value_epsg == '32630' or value_epsg == ' 32631' or value_epsg == '32632' or value_epsg == '3857' or value_epsg == '4326' or value_epsg == '4258' or value_epsg == '32620' or value_epsg == '2970' or value_epsg == '2972' or value_epsg == '2973' or value_epsg == '2975' or value_epsg == '32622' or value_epsg == '32740' or value_epsg == '32738' or value_epsg == '4471' or value_epsg == '32621': feedback.pushInfo('EPSG code' + value_epsg) tab = [] for f in source.getFeatures(): col_select = f[field_insee], (''.join( (c for c in unicodedata.normalize('NFD', f[field_commune]) if unicodedata.category(c) != 'Mn'))) # Insere chaque ligne du CSV dans le tableau tab.append(col_select) #Permet la suppression des doublons et le tri Lt = sorted(set(tab)) print(Lt) for c_insee, n_couche in Lt: urlWithParams = "url=http://inspire.cadastre.gouv.fr/scpc/" + c_insee + ".wms?contextualWMSLegend=0&crs=EPSG:" + value_epsg + "&dpiMode=7&featureCount=10&format=image/png&layers=VOIE_COMMUNICATION&styles=&maxHeight=1024&maxWidth=1280" rlayer = QgsRasterLayer( urlWithParams, 'Petites_voies_de_communication_' + n_couche + '_' + c_insee, 'wms') feedback.pushInfo('Category :' + n_couche + ' - ' + c_insee) feedback.pushInfo('Validity of WMS : %s' % rlayer.isValid()) if not rlayer.isValid(): print('Petites_voies_de_communication_' + n_couche + '_' + c_insee + ' failed to load!') feedback.pushInfo('WMS INVALID : Cadastre_' + n_couche + '_' + c_insee) else: #Source : https://gis.stackexchange.com/questions/342802/loading-openstreetmap-in-pyqgis output_layers = [] output_layers.append(rlayer) context.temporaryLayerStore().addMapLayer(rlayer) context.addLayerToLoadOnCompletion( rlayer.id(), QgsProcessingContext.LayerDetails( 'Petites_voies_de_communication_' + n_couche + '_' + c_insee, context.project(), self.OUTPUT_LAYERS)) else: feedback.pushInfo('Error EPSG code') # Return the results of the algorithm. In this case our only result is # the feature sink which contains the processed features, but some # algorithms may return multiple feature sinks, calculated numeric # statistics, etc. These should all be included in the returned # dictionary, with keys matching the feature corresponding parameter # or output names. # At the end of the processAlgorithmn # Add the layer to the project return {}
def test_check_validity(self): """Test that the output invalid contains the error reason""" polygon_layer = self._make_layer('Polygon') self.assertTrue(polygon_layer.startEditing()) f = QgsFeature(polygon_layer.fields()) f.setAttributes([1]) # Flake! f.setGeometry( QgsGeometry.fromWkt('POLYGON ((0 0, 2 2, 0 2, 2 0, 0 0))')) self.assertTrue(f.isValid()) f2 = QgsFeature(polygon_layer.fields()) f2.setAttributes([1]) f2.setGeometry( QgsGeometry.fromWkt( 'POLYGON((1.1 1.1, 1.1 2.1, 2.1 2.1, 2.1 1.1, 1.1 1.1))')) self.assertTrue(f2.isValid()) self.assertTrue(polygon_layer.addFeatures([f, f2])) polygon_layer.commitChanges() polygon_layer.rollBack() self.assertEqual(polygon_layer.featureCount(), 2) QgsProject.instance().addMapLayers([polygon_layer]) alg = self.registry.createAlgorithmById('qgis:checkvalidity') context = QgsProcessingContext() context.setProject(QgsProject.instance()) feedback = ConsoleFeedBack() self.assertIsNotNone(alg) parameters = {} parameters['INPUT_LAYER'] = polygon_layer.id() parameters['VALID_OUTPUT'] = 'memory:' parameters['INVALID_OUTPUT'] = 'memory:' parameters['ERROR_OUTPUT'] = 'memory:' # QGIS method parameters['METHOD'] = 1 ok, results = execute(alg, parameters, context=context, feedback=feedback) self.assertTrue(ok) invalid_layer = QgsProcessingUtils.mapLayerFromString( results['INVALID_OUTPUT'], context) self.assertEqual(invalid_layer.fields().names()[-1], '_errors') self.assertEqual(invalid_layer.featureCount(), 1) f = next(invalid_layer.getFeatures()) self.assertEqual(f.attributes(), [1, 'segments 0 and 2 of line 0 intersect at 1, 1']) # GEOS method parameters['METHOD'] = 2 ok, results = execute(alg, parameters, context=context, feedback=feedback) self.assertTrue(ok) invalid_layer = QgsProcessingUtils.mapLayerFromString( results['INVALID_OUTPUT'], context) self.assertEqual(invalid_layer.fields().names()[-1], '_errors') self.assertEqual(invalid_layer.featureCount(), 1) f = next(invalid_layer.getFeatures()) self.assertEqual(f.attributes(), [1, 'Self-intersection'])
def testInputs(self): """ Test creation of script with algorithm inputs """ alg = RAlgorithm(description_file=os.path.join(test_data_path, 'test_algorithm_2.rsx')) alg.initAlgorithm() context = QgsProcessingContext() feedback = QgsProcessingFeedback() # enum evaluation script = alg.build_import_commands({'in_enum': 0}, context, feedback) self.assertIn('in_enum <- 0', script) # boolean evaluation script = alg.build_import_commands({'in_bool': True}, context, feedback) self.assertIn('in_bool <- TRUE', script) script = alg.build_import_commands({'in_bool': False}, context, feedback) self.assertIn('in_bool <- FALSE', script) # number evaluation script = alg.build_import_commands({'in_number': None}, context, feedback) self.assertIn('in_number <- NULL', script) script = alg.build_import_commands({'in_number': 5}, context, feedback) self.assertIn('in_number <- 5.0', script) script = alg.build_import_commands({'in_number': 5.5}, context, feedback) self.assertIn('in_number <- 5.5', script) # folder destination script = alg.build_import_commands( {'param_folder_dest': '/tmp/processing/test_algorithm_2_r/'}, context, feedback) # file destination script = alg.build_import_commands( { 'param_html_dest': '/tmp/processing/test_algorithm_2_r/dest.html' }, context, feedback) self.assertIn( 'param_html_dest <- "/tmp/processing/test_algorithm_2_r/dest.html"', script) script = alg.build_import_commands( { 'param_file_dest': '/tmp/processing/test_algorithm_2_r/dest.file' }, context, feedback) self.assertIn( 'param_file_dest <- "/tmp/processing/test_algorithm_2_r/dest.file"', script) script = alg.build_import_commands( {'param_csv_dest': '/tmp/processing/test_algorithm_2_r/dest.csv'}, context, feedback) self.assertIn( 'param_csv_dest <- "/tmp/processing/test_algorithm_2_r/dest.csv"', script)
def _export_basemap(self) -> bool: self.total_progress_updated.emit(0, 1, self.trUtf8("Creating base map…")) if not self._export_basemap_requirements_check(): return False project = QgsProject.instance() basemap_extent = self.area_of_interest.boundingBox() if basemap_extent.isNull() or not basemap_extent.isFinite(): self.warning.emit( self.tr("Failed to create basemap"), self.tr( "Cannot create basemap for the given area of interest."), ) return False if not self.project_configuration.base_map_layer.strip(): self.warning.emit( self.tr("Failed to create basemap"), self. tr("No basemap layer selected. Please check the project configuration." ).format(self.project_configuration.base_map_layer), ) return False extent = basemap_extent base_map_type = self.project_configuration.base_map_type if base_map_type == ProjectProperties.BaseMapType.SINGLE_LAYER: basemap_layer = project.mapLayer( self.project_configuration.base_map_layer) if not basemap_layer: self.warning.emit( self.tr("Failed to create basemap"), self. tr('Cannot find the configured base layer with id "{}". Please check the project configuration.' ).format(self.project_configuration.base_map_layer), ) return False # we need to transform the extent to match the one of the selected layer extent = QgsCoordinateTransform( QgsCoordinateReferenceSystem(self.area_of_interest_crs), project.crs(), project, ).transformBoundingBox(basemap_extent) elif base_map_type == ProjectProperties.BaseMapType.MAP_THEME: if not project.mapThemeCollection().hasMapTheme( self.project_configuration.base_map_theme): self.warning.emit( self.tr("Failed to create basemap"), self. tr('Cannot find the configured base theme with name "{}". Please check the project configuration.' ).format(self.project_configuration.base_map_theme), ) return False extent_string = "{},{},{},{}".format( extent.xMinimum(), extent.xMaximum(), extent.yMinimum(), extent.yMaximum(), ) alg = (QgsApplication.instance().processingRegistry(). createAlgorithmById("native:rasterize")) params = { "EXTENT": extent_string, "EXTENT_BUFFER": 0, "TILE_SIZE": self.project_configuration.base_map_tile_size, "MAP_UNITS_PER_PIXEL": self.project_configuration.base_map_mupp, "MAKE_BACKGROUND_TRANSPARENT": False, "OUTPUT": os.path.join(self.export_folder, "basemap.gpkg"), } if base_map_type == ProjectProperties.BaseMapType.SINGLE_LAYER: params["LAYERS"] = [self.project_configuration.base_map_layer] elif base_map_type == ProjectProperties.BaseMapType.MAP_THEME: params["MAP_THEME"] = self.project_configuration.base_map_theme feedback = QgsProcessingFeedback() context = QgsProcessingContext() context.setProject(QgsProject.instance()) results, ok = alg.run(params, context, feedback) if not ok: self.warning.emit(self.tr("Failed to create basemap"), feedback.textLog()) return False new_layer = QgsRasterLayer(results["OUTPUT"], self.tr("Basemap")) resample_filter = new_layer.resampleFilter() resample_filter.setZoomedInResampler(QgsCubicRasterResampler()) resample_filter.setZoomedOutResampler(QgsBilinearRasterResampler()) self.project_configuration.project.addMapLayer(new_layer, False) layer_tree = QgsProject.instance().layerTreeRoot() layer_tree.insertLayer(len(layer_tree.children()), new_layer) return True
def testGdalTranslate(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() source = os.path.join(testDataPath, 'dem.tif') translate_alg = translate() translate_alg.initAlgorithm() # with no NODATA value self.assertEqual( translate_alg.getConsoleCommands({'INPUT': source, 'OUTPUT': 'd:/temp/check.jpg'}, context, feedback), ['gdal_translate', '-ot Float32 -of JPEG ' + source + ' ' + 'd:/temp/check.jpg']) # with NODATA value self.assertEqual( translate_alg.getConsoleCommands({'INPUT': source, 'NODATA': 9999, 'OUTPUT': 'd:/temp/check.jpg'}, context, feedback), ['gdal_translate', '-a_nodata 9999.0 ' + '-ot Float32 -of JPEG ' + source + ' ' + 'd:/temp/check.jpg']) # with "0" NODATA value self.assertEqual( translate_alg.getConsoleCommands({'INPUT': source, 'NODATA': 0, 'OUTPUT': 'd:/temp/check.jpg'}, context, feedback), ['gdal_translate', '-a_nodata 0.0 ' + '-ot Float32 -of JPEG ' + source + ' ' + 'd:/temp/check.jpg']) # with target srs self.assertEqual( translate_alg.getConsoleCommands({'INPUT': source, 'TARGET_CRS': 'EPSG:3111', 'OUTPUT': 'd:/temp/check.jpg'}, context, feedback), ['gdal_translate', '-a_srs EPSG:3111 ' + '-ot Float32 -of JPEG ' + source + ' ' + 'd:/temp/check.jpg']) # with target srs self.assertEqual( translate_alg.getConsoleCommands({'INPUT': source, 'TARGET_CRS': 'EPSG:3111', 'OUTPUT': 'd:/temp/check.jpg'}, context, feedback), ['gdal_translate', '-a_srs EPSG:3111 ' + '-ot Float32 -of JPEG ' + source + ' ' + 'd:/temp/check.jpg']) # with copy subdatasets self.assertEqual( translate_alg.getConsoleCommands({'INPUT': source, 'COPY_SUBDATASETS': True, 'OUTPUT': 'd:/temp/check.tif'}, context, feedback), ['gdal_translate', '-sds ' + '-ot Float32 -of GTiff ' + source + ' ' + 'd:/temp/check.tif'])
def createContext(): """ Creates a default processing context """ context = QgsProcessingContext() context.setProject(QgsProject.instance()) invalid_features_method = ProcessingConfig.getSetting(ProcessingConfig.FILTER_INVALID_GEOMETRIES) if invalid_features_method is None: invalid_features_method = QgsFeatureRequest.GeometryAbortOnInvalid context.setInvalidGeometryCheck(invalid_features_method) def raise_error(f): raise GeoAlgorithmExecutionException(QCoreApplication.translate("FeatureIterator", 'Features with invalid geometries found. Please fix these geometries or specify the "Ignore invalid input features" flag')) context.setInvalidGeometryCallback(raise_error) def raise_transform_error(f): raise GeoAlgorithmExecutionException(QCoreApplication.translate("FeatureIterator", 'Encountered a transform error when reprojecting feature with id {}.'.format(f.id()))) context.setTransformErrorCallback(raise_transform_error) settings = QgsSettings() context.setDefaultEncoding(settings.value("/Processing/encoding", "System")) return context
def produce_warped_tif(self, write_result): self.out("produce_warped_tif()") """ ASCII to warped TIF """ # very important! if path.exists(self._full_tif_filename): #self.out("removing old version of warped TIF before creating a new one...") os.remove(self._full_tif_filename) proj_radolan = self._model.projection_radolan """ METHOD Options: 0 - near 1 - bilinear 2 - cubic 3 - cubicspline 4 - lanczos Eigentlich Default: 0 - aber man muss es angeben (QGIS 2.14 "Essen") RTYPE: default: 5 = Float32 COMPRESS(GeoTIFF options. Compression type:) 0 - NONE 1 - JPEG 2 - LZW 3 - PACKBITS 4 - DEFLATE wohl kein Default, also angeben """ # Standard (certain) params: params = { "INPUT": self._full_asc_filename, "SOURCE_SRS": proj_radolan, #"DEST_SRS": 'EPSG:3035', # QGIS 2? "TARGET_CRS": 'EPSG:3035', "METHOD": 0, "COMPRESS": 4 } """ useful tip: If you don't need to use the output for further elaborations, you may save it as memory layer. For doing this you only need to set the 'output' parameter as None: first = processing.runalg("gdalogr:warpreproject", { "INPUT": ... , "OUTPUT": None } ) Instead, if you want to use the output, you may easily do this by giving it a name and then by calling it with getObject(): second = processing.getObject( first['OUTPUT'] ) -> https://gis.stackexchange.com/questions/224389/pyqgis-processing-runalg-release-input-in-windows """ #params['OUTPUT'] = self._full_tif_filename if write_result else None params['OUTPUT'] = self._full_tif_filename if write_result else 'none' # in QGIS 3. Verrückt # New GdalUtils version with some additional parameters! (RAST_EXT, ...) #if version >= 2000000: # Other possibility: #>>> QgsExpressionContextUtils.globalScope().variableNames(): show all avail vars #>>> QgsExpressionContextUtils.globalScope().variable('qgis_version') # with name # out: u'2.99.0-Master' #>>> QgsExpressionContextUtils.globalScope().variable('qgis_version_no') # better """ ............................................................. HERE WE CAN SEND A GDAL CALL ADAPTED TO THE CORRESPONDING VERION! ............................................................. """ add_additional_keys = False try: version = GdalUtils.version() if platform.system() == 'Windows': system_name = "{} {}".format(platform.system(), platform.release()) raise OSError("Running on '{}'".format(system_name)) #except AttributeError as ex: # ex: class GdalUtils has no attribute 'version' except AttributeError: self.out("WARN: GdalUtils.version could not determined (older version?)", False) self.out("continue without dict keys 'RAST_EXT', 'EXT_CRS'", False) except OSError as e: self.out(e, False) self.out("continue without dict keys 'RAST_EXT', 'EXT_CRS'", False) # Nur wenn Try OK: section for determining the extent of input raster by creating layer datatype else: self.out("GdalUtils.version is {}".format(version)) # Result for # Dev-Version/Linux: 2010200 # 2.18.15 Las Palmas: 2020300 # Für diese Versionsnummer ging es nämlich NICHT! (openSUSE Leap 42.3, obige QGIS-Version) if version != 2020300: add_additional_keys = True # Ende try-except-else-Block if add_additional_keys: # Make layer type from ASCII file to determine the mandatory 'extent': asc_layer = self._create_QGSRasterLayer_with_projection(proj_radolan) # avoid projection dialog extent = asc_layer.extent() extent_params_as_string = "%f,%f,%f,%f" \ % (extent.xMinimum(), extent.xMaximum(), extent.yMinimum(), extent.yMaximum() ) # insert these params later for newer GDAL versions: params['RAST_EXT'] = extent_params_as_string ### NEW! for new gdal versions. params['EXT_CRS' ] = proj_radolan ### NEW! for new gdal versions. MUST be Radolan-Proj.!!! self.out(" -> inserting new keys 'RAST_EXT', 'EXT_CRS'") # Diagnose: print("### Dict params are:\n ", params) # For overview of the parameters use in QGIS python console: # processing.alghelp("gdalogr:warpreproject") #target = processing.runalg("gdalogr:warpreproject", params ) # return: dict QGIS 2 target = processing.run("gdal:warpreproject", params) # QGIS 3 fallback = False # TIF shouldt be written but doesn't exists: if write_result and not path.exists(self._full_tif_filename): fallback = True # Normal mode: return Memory Layer: if not fallback: #self._result = processing.getObject(target["OUTPUT"]) # key of dict, QGIS 2 context = QgsProcessingContext() self._result = QgsProcessingUtils.mapLayerFromString(target["OUTPUT"], context) #print("result =", self._result) return #return self._result """ When warped TIF wasn't created: FALLBACK MODE without dict normally not, when dict is working The normal way is positive tested on a QGIS-dev on Linux 2.12.99. But the following fallback way need to implemented for the following configuration: also on Linux, Python-Version 2.7.12 (default, Jul 01 2016, 15:36:53) [GCC] QGIS-Version: 2.8.2 "Wien", exported """ #return self._produce_warped_tif_fallback(write_result)
def testFeatureSourceInput(self): # create a memory layer and add to project and context layer = QgsVectorLayer( "Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer", "testmem", "memory") self.assertTrue(layer.isValid()) pr = layer.dataProvider() f = QgsFeature() f.setAttributes(["test", 123]) f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(100, 200))) f2 = QgsFeature() f2.setAttributes(["test2", 457]) f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(110, 200))) self.assertTrue(pr.addFeatures([f, f2])) self.assertEqual(layer.featureCount(), 2) # select first feature layer.selectByIds([next(layer.getFeatures()).id()]) self.assertEqual(len(layer.selectedFeatureIds()), 1) QgsProject.instance().addMapLayer(layer) context = QgsProcessingContext() context.setProject(QgsProject.instance()) alg = QgsApplication.processingRegistry().createAlgorithmById( 'grass7:v.buffer') self.assertIsNotNone(alg) temp_file = os.path.join(self.temp_dir, 'grass_output_sel.shp') parameters = { 'input': QgsProcessingFeatureSourceDefinition('testmem', True), 'cats': '', 'where': '', 'type': [0, 1, 4], 'distance': 1, 'minordistance': None, 'angle': 0, 'column': None, 'scale': 1, 'tolerance': 0.01, '-s': False, '-c': False, '-t': False, 'output': temp_file, 'GRASS_REGION_PARAMETER': None, 'GRASS_SNAP_TOLERANCE_PARAMETER': -1, 'GRASS_MIN_AREA_PARAMETER': 0.0001, 'GRASS_OUTPUT_TYPE_PARAMETER': 0, 'GRASS_VECTOR_DSCO': '', 'GRASS_VECTOR_LCO': '' } feedback = QgsProcessingFeedback() results, ok = alg.run(parameters, context, feedback) self.assertTrue(ok) self.assertTrue(os.path.exists(temp_file)) # make sure that layer has correct features res = QgsVectorLayer(temp_file, 'res') self.assertTrue(res.isValid()) self.assertEqual(res.featureCount(), 1) QgsProject.instance().removeMapLayer(layer)
def processAlgorithm(self, parameters, context, feedback): # extract input parameters alg = self.parameterAsEnum(parameters, self.INPUT_ALG_NAME, context) extent = self.parameterAsVectorLayer(parameters, self.INPUT_EXTENT, context) raster_1_id = self.parameterAsString(parameters, self.INPUT_RASTER_1, context) raster_1 = QgsProject.instance().mapLayer(raster_1_id) raster_2_id = self.parameterAsString(parameters, self.INPUT_RASTER_2, context) raster_2 = QgsProject.instance().mapLayer(raster_2_id) (sink, self.dest_id) = self.parameterAsSink( parameters, self.OUTPUT_BUFFER, context, QgsFields(), extent.wkbType(), extent.sourceCrs(), ) outputFile = self.parameterAsRasterLayer( parameters, self.OUTPUT_CHANGES, context ) # create a temporary vector layer tmp = tempfile.mkdtemp() path_roi = os.path.join(tmp, "roi.shp") writer = QgsVectorFileWriter( path_roi, "UTF-8", QgsFields(), QgsWkbTypes.Polygon, extent.sourceCrs(), "ESRI Shapefile", ) # create buffered extent and update temporary shp for detector for feature in extent.getFeatures(): geom = feature.geometry() buffer = geom.buffer( 10, 100, QgsGeometry.CapFlat, QgsGeometry.JoinStyleMiter, 100 ) feature.setGeometry(buffer) feature.setFields(QgsFields()) sink.addFeature(feature) writer.addFeature(feature) del writer # run change detector path1 = raster_1.source() path2 = raster_2.source() detector = LittoDynChangeDetectorPca(path1, path2, path_roi) if alg == 1: detector = LittoDynChangeDetectorEvi(path1, path2, path_roi) elif alg == 2: detector = LittoDynChangeDetectorNdvi(path1, path2, path_roi) elif alg == 3: detector = LittoDynChangeDetectorNgrdi(path1, path2, path_roi) elif alg == 4: detector = LittoDynChangeDetectorNormEuclid(path1, path2, path_roi) elif alg == 5: detector = LittoDynChangeDetectorNormCorr(path1, path2, path_roi) elif alg == 6: detector = LittoDynChangeDetectorNormCos(path1, path2, path_roi) detector.detect() # store output layers in group alg_name = self.options[alg].lower().replace(" ", "_") if Qgis.QGIS_VERSION_INT >= 31500: name = "{}_{}_{}".format(raster_1.name(), raster_2.name(), alg_name) ProcessingConfig.setSettingValue(ProcessingConfig.RESULTS_GROUP_NAME, name) # save result in temporary file tmp = tempfile.mkdtemp() path_changes = os.path.join(tmp, "{}_changes.tif".format(alg_name)) detector.save(path_changes) rl = QgsRasterLayer(path_changes, "{}_changes".format(alg_name), "gdal") context.temporaryLayerStore().addMapLayer(rl) context.addLayerToLoadOnCompletion( rl.id(), QgsProcessingContext.LayerDetails( "{}_changes".format(alg_name), context.project(), self.OUTPUT_CHANGES ), ) return { self.OUTPUT_CHANGES: rl.id(), self.OUTPUT_BUFFER: self.dest_id, self.OUTPUT_CHANGES: rl.id(), }
def check_algorithm(self, name, defs): """ Will run an algorithm definition and check if it generates the expected result :param name: The identifier name used in the test output heading :param defs: A python dict containing a test algorithm definition """ self.vector_layer_params = {} QgsProject.instance().clear() if 'project' in defs: full_project_path = os.path.join(processingTestDataPath(), defs['project']) project_read_success = QgsProject.instance().read( full_project_path) self.assertTrue(project_read_success, 'Failed to load project file: ' + defs['project']) if 'project_crs' in defs: QgsProject.instance().setCrs( QgsCoordinateReferenceSystem(defs['project_crs'])) else: QgsProject.instance().setCrs(QgsCoordinateReferenceSystem()) if 'ellipsoid' in defs: QgsProject.instance().setEllipsoid(defs['ellipsoid']) else: QgsProject.instance().setEllipsoid('') params = self.load_params(defs['params']) print('Running alg: "{}"'.format(defs['algorithm'])) alg = QgsApplication.processingRegistry().createAlgorithmById( defs['algorithm']) parameters = {} if isinstance(params, list): for param in zip(alg.parameterDefinitions(), params): parameters[param[0].name()] = param[1] else: for k, p in params.items(): parameters[k] = p for r, p in list(defs['results'].items()): if 'in_place_result' not in p or not p['in_place_result']: parameters[r] = self.load_result_param(p) expectFailure = False if 'expectedFailure' in defs: exec(('\n'.join(defs['expectedFailure'][:-1])), globals(), locals()) expectFailure = eval(defs['expectedFailure'][-1]) if 'expectedException' in defs: expectFailure = True # ignore user setting for invalid geometry handling context = QgsProcessingContext() context.setProject(QgsProject.instance()) if 'skipInvalid' in defs and defs['skipInvalid']: context.setInvalidGeometryCheck( QgsFeatureRequest.GeometrySkipInvalid) feedback = QgsProcessingFeedback() print('Algorithm parameters are {}'.format(parameters)) # first check that algorithm accepts the parameters we pass... ok, msg = alg.checkParameterValues(parameters, context) self.assertTrue( ok, 'Algorithm failed checkParameterValues with result {}'.format(msg)) if expectFailure: try: results, ok = alg.run(parameters, context, feedback) self.check_results(results, context, parameters, defs['results']) if ok: raise _UnexpectedSuccess except Exception: pass else: results, ok = alg.run(parameters, context, feedback) self.assertTrue( ok, 'params: {}, results: {}'.format(parameters, results)) self.check_results(results, context, parameters, defs['results'])
def startWorker(self): """Initialises and starts.""" self.inputbuffers = {} self.referencebuffers = {} self.polycount = {} self.completeness = {} self.miscodings = {} self.statistics = {} self.testcounter = 0 try: layerindex = self.inputLayer.currentIndex() layerId = self.inputLayer.itemData(layerindex) self.inputlayer = QgsProject.instance().mapLayer(layerId) if self.inputlayer is None: self.showError(self.tr('No input layer defined')) return refindex = self.referenceLayer.currentIndex() reflayerId = self.referenceLayer.itemData(refindex) self.reflayer = QgsProject.instance().mapLayer(reflayerId) if layerId == reflayerId: self.showInfo('The reference layer must be different' ' from the input layer!') return if self.reflayer is None: self.showError(self.tr('No reference layer defined')) return if self.inputlayer.sourceCrs().authid() != self.reflayer.sourceCrs( ).authid(): self.showWarning('Layers must have the same CRS - Input: ' + str(self.inputlayer.sourceCrs().authid()) + ' Reference: ' + str(self.reflayer.sourceCrs().authid())) return if self.reflayer.sourceCrs().isGeographic(): self.showWarning('Geographic CRS used -' + ' computations will be in decimal degrees!') # Algorithms self.bufferalg = QgsApplication.processingRegistry().algorithmById( 'native:buffer') #self.bufferalg=QgsApplication.processingRegistry().algorithmById('qgis:buffer') self.unionalg = QgsApplication.processingRegistry().algorithmById( 'qgis:union') self.intersectionalg = QgsApplication.processingRegistry( ).algorithmById('qgis:intersection') self.differencealg = QgsApplication.processingRegistry( ).algorithmById('qgis:difference') self.multitosinglealg = QgsApplication.processingRegistry( ).algorithmById('qgis:multiparttosingleparts') self.statalg = QgsApplication.processingRegistry().algorithmById( 'qgis:statisticsbycategories') # Calculate the total length of lines in the layers self.inpgeomlength = 0 for f in self.inputlayer.getFeatures(): self.inpgeomlength = self.inpgeomlength + f.geometry().length() self.refgeomlength = 0 for f in self.reflayer.getFeatures(): self.refgeomlength = self.refgeomlength + f.geometry().length() # Number of steps and radii steps = self.stepsSB.value() startradius = self.startRadiusSB.value() endradius = self.endRadiusSB.value() delta = (endradius - startradius) / (steps - 1) self.radiuses = [] for step in range(steps): self.radiuses.append(startradius + step * delta) #self.radiuses = [10,20,50] #self.showInfo(str(self.radiuses)) feedback = QgsProcessingFeedback() selectedinputonly = self.selectedFeaturesCheckBox.isChecked() selectedrefonly = self.selectedRefFeaturesCheckBox.isChecked() #plugincontext = dataobjects.createContext(feedback) #self.showInfo('Plugin context: ' + str(plugincontext)) #self.showInfo('GUI thread: ' + str(QThread.currentThread()) + ' ID: ' + str(QThread.currentThreadId())) ###### Testing QgsTask!!! # I følge oppskrifta på opengis.ch context = QgsProcessingContext() #context = plugincontext #self.showInfo('Normal context: ' + str(context)) #context.setProject(QgsProject.instance()) for radius in self.radiuses: # Buffer input # Works! inlayercopy = QgsVectorLayer(self.inputlayer.source(), 'in' + str(radius), self.inputlayer.providerType()) ##inlayercopy = self.copylayer(self.inputlayer, 'in' + str(radius)) params = { 'INPUT': inlayercopy, #'INPUT': self.inputlayer, 'DISTANCE': radius, #'OUTPUT':'/home/havatv/test.shp' 'OUTPUT': 'memory:InputBuffer' } task = QgsProcessingAlgRunnerTask(self.bufferalg, params, context) ##task = QgsProcessingAlgRunnerTask(self.bufferalg,params,context,feedback) # Add a few extra parameters (context, radius and "input") using "partial" task.executed.connect( partial(self.buffer_executed, context, radius, self.INPUT)) QgsApplication.taskManager().addTask(task) self.showInfo('Start Input buffer: ' + str(radius)) # Buffer reference # Works! reflayercopy = QgsVectorLayer(self.reflayer.source(), 'ref' + str(radius), self.reflayer.providerType()) #reflayercopy = self.copylayer(self.reflayer, 'ref' + str(radius)) params = { 'INPUT': reflayercopy, #'INPUT': self.reflayer, 'DISTANCE': radius, #'OUTPUT':'/home/havatv/test.shp' 'OUTPUT': 'memory:ReferenceBuffer' } task = QgsProcessingAlgRunnerTask(self.bufferalg, params, context) #task = QgsProcessingAlgRunnerTask(self.bufferalg,params,context,feedback) # Add a few extra parameters (context, radius and "reference") using "partial" task.executed.connect( partial(self.buffer_executed, context, radius, self.REF)) QgsApplication.taskManager().addTask(task) self.showInfo('Start Ref buffer: ' + str(radius)) ##task.begun.connect(self.task_begun) ##task.taskCompleted.connect(self.task_completed) ##task.progressChanged.connect(self.task_progress) ##task.taskTerminated.connect(self.task_stopped) #iteration = 5 # Identifiserer hvilken iterasjon det er snakk om ## I følge oppskrifta på opengis.ch (partial legger inn context som første parameter): ## context ser ut til å være helt nødvendig! #task.executed.connect(partial(self.task_executed, context, iteration)) #self.button_box.button(QDialogButtonBox.Ok).setEnabled(False) #self.button_box.button(QDialogButtonBox.Close).setEnabled(False) #self.button_box.button(QDialogButtonBox.Cancel).setEnabled(True) except: import traceback self.showError(traceback.format_exc()) else: pass
def processAlgorithm(self, parameters, context, feedback): self.dest_id = None # Parameters # lighting = self.parameterAsVectorLayer(parameters, self.LIGHTING, context) lighting_source, lighting_layer = qgsTreatments.parameterAsSourceLayer( self, parameters, self.LIGHTING, context, feedback=feedback) if not lighting_source: raise QgsProcessingException("No lighting layer") fieldname = self.parameterAsString(parameters, self.FLUX_FIELD, context) if not fieldname: raise QgsProcessingException("No field given for light flux") flux_div_flag = self.parameterAsBool(parameters, self.FLUX_DIV, context) reporting, reporting_layer = qgsTreatments.parameterAsSourceLayer( self, parameters, self.REPORTING, context, feedback=feedback) if not reporting: raise QgsProcessingException("No reporting layer") init_reporting_fields = reporting_layer.fields().names() surface, surface_layer = qgsTreatments.parameterAsSourceLayer( self, parameters, self.SURFACE, context, feedback=feedback) dissolve_flag = self.parameterAsBool(parameters, self.DISSOLVE, context) clip_val = self.parameterAsInt(parameters, self.CLIP_DISTANCE, context) reporting_fields = self.parameterAsFields(parameters, self.REPORTING_FIELDS, context) skip_flag = self.parameterAsBool(parameters, self.SKIP_EMPTY, context) min_area = self.parameterAsDouble(parameters, self.MIN_AREA, context) min_lamps = self.parameterAsInt(parameters, self.MIN_NB_LAMPS, context) # Reprojection if needed light_crs = lighting_source.sourceCrs().authid() reporting_crs = reporting.sourceCrs() # reporting_crs = reporting.dataProvider().sourceCrs() if reporting_crs.isGeographic(): raise QgsProcessingException( "Reporting CRS must be a projection (not lat/lon)") feedback.pushDebugInfo("reporting_crs = " + str(type(reporting_crs))) feedback.pushDebugInfo("reporting_crs = " + str(reporting_crs)) reporting_crs_id = reporting_crs.authid() feedback.pushDebugInfo("reporting_crs_id = " + str(type(reporting_crs_id))) feedback.pushDebugInfo("reporting_crs_id = " + str(reporting_crs_id)) if light_crs != reporting_crs_id: lighting_path = QgsProcessingUtils.generateTempFilename( 'light_reproj.gpkg') qgsTreatments.applyReprojectLayer(lighting_layer, reporting_crs, lighting_path, context=context, feedback=feedback) lighting_layer = lighting_path if surface: surface_crs = surface.sourceCrs().authid() if reporting_crs_id != surface_crs: surface_reproj = QgsProcessingUtils.generateTempFilename( 'surface_reproj.gpkg') qgsTreatments.applyReprojectLayer(surface_layer, reporting_crs, surface_reproj, context=context, feedback=feedback) surface_fixed = QgsProcessingUtils.generateTempFilename( 'surface_fixed.gpkg') qgsTreatments.fixGeometries(surface_reproj, surface_fixed, context=context, feedback=feedback) surface_layer = qgsUtils.loadVectorLayer(surface_fixed) qgsTreatments.createSpatialIndex(surface_layer, context=context, feedback=feedback) # Output fields initialization nb_lamps_field = QgsField(self.NB_LAMPS, QVariant.Int) flux_sum_field = QgsField(self.FLUX_SUM, QVariant.Double) surface_field = QgsField(self.SURFACE_AREA, QVariant.Double) flux_den_field = QgsField(self.FLUX_DEN, QVariant.Double) out_fields = QgsFields() for f in reporting_layer.fields(): if f.name() in reporting_fields: # feedback.pushDebugInfo("f2 = " + str( f.name())) out_fields.append(f) out_fields.append(nb_lamps_field) out_fields.append(flux_sum_field) out_fields.append(surface_field) out_fields.append(flux_den_field) (sink, self.dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, out_fields, reporting.wkbType(), reporting.sourceCrs()) # Progess bar step nb_feats = reporting.featureCount() total = 100.0 / nb_feats if nb_feats else 0 # Clip according to distance to lighting if clip_val: buffered_path = QgsProcessingUtils.generateTempFilename( 'light_buf.gpkg') buffered = qgsTreatments.applyBufferFromExpr(lighting_layer, clip_val, buffered_path, context=context, feedback=feedback) clipped_path = QgsProcessingUtils.generateTempFilename( 'reporting_clip.gpkg') qgsTreatments.createSpatialIndex(reporting_layer, context=context, feedback=feedback) clipped = qgsTreatments.applyVectorClip(reporting_layer, buffered_path, clipped_path, context=context, feedback=feedback) reporting_layer = clipped_path # Get reporting units count per light if flux_div_flag: if 'ID' in init_reporting_fields: id_field = 'ID' elif 'fid' in init_reporting_fields: id_field = 'fid' else: raise QgsProcessingException( "ID field does not exist in reporting layer") qgsTreatments.createSpatialIndex(lighting_layer, context=context, feedback=feedback) joined_light_path = QgsProcessingUtils.generateTempFilename( 'joined_light.gpkg') qgsTreatments.joinByLocSummary(lighting_layer, reporting_layer, joined_light_path, [id_field], summaries=[0], predicates=[0], context=context, feedback=feedback) joined_light_layer = qgsUtils.loadVectorLayer(joined_light_path) id_cpt_name = id_field + '_count' def funcDiv(f): if f[fieldname]: try: flux = float(f[fieldname]) nb_units = int(f[id_cpt_name]) return flux / nb_units except ValueError: return None else: return None qgsUtils.createOrUpdateField(joined_light_layer, funcDiv, self.FLUX_DIV_FIELD) lighting_layer, fieldname = joined_light_layer, self.FLUX_DIV_FIELD # Join light points summary by reporting unit joined_path = QgsProcessingUtils.generateTempFilename('joined.gpkg') # SUM = 5 summaries = [0, 1, 2, 3, 5, 6] qgsTreatments.createSpatialIndex(reporting_layer, context=context, feedback=feedback) joined = qgsTreatments.joinByLocSummary(reporting_layer, lighting_layer, joined_path, [fieldname], summaries, predicates=[0], context=context, feedback=feedback) joined_layer = qgsUtils.loadVectorLayer(joined_path) nb_lamps_fieldname = fieldname + "_count" flux_field_sum = fieldname + "_sum" # Set context and feedback if not context: context = QgsProcessingContext() context = context.setInvalidGeometryCheck( QgsFeatureRequest.GeometryNoCheck) multi_feedback = QgsProcessingMultiStepFeedback(nb_feats, feedback) # Iteration on each reporting unit qgsTreatments.createSpatialIndex(joined_layer, context=context, feedback=feedback) for current, feat in enumerate(joined_layer.getFeatures()): if feedback.isCanceled(): break f_geom = feat.geometry() f_area = f_geom.area() f_id = feat.id() nb_lamps = feat[nb_lamps_fieldname] flux_sum = feat[flux_field_sum] if skip_flag and flux_sum == 0: continue if f_area < min_area: continue if nb_lamps < min_lamps: continue try: if surface: # Clip surface layer to reporting feature boundaries to retrieve intersecting area nb_steps = 4 if dissolve_flag else 3 mmf = QgsProcessingMultiStepFeedback( nb_steps, multi_feedback) joined_layer.selectByIds([f_id]) suffix = "_" + str(f_id) + ".gpkg" input_feat = QgsProcessingUtils.generateTempFilename( "selection" + suffix) qgsTreatments.saveSelectedAttributes(joined_layer, input_feat, context=context, feedback=mmf) mmf.setCurrentStep(1) # input_feat = QgsProcessingFeatureSourceDefinition(joined_layer.id(),True) clipped_path = QgsProcessingUtils.generateTempFilename( "clipped" + str(f_id) + ".gpkg") clipped = qgsTreatments.applyVectorClip(surface_layer, input_feat, clipped_path, context=context, feedback=mmf) mmf.setCurrentStep(2) if dissolve_flag: feat_surface_path = QgsProcessingUtils.generateTempFilename( "dissolved" + str(f_id) + ".gpkg") qgsTreatments.dissolveLayer(clipped, feat_surface_path, context=context, feedback=mmf) mmf.setCurrentStep(3) else: feat_surface_path = clipped_path feat_surface_layer = qgsUtils.loadVectorLayer( feat_surface_path) joined_layer.removeSelection() surface_area = 0 for surface_feat in feat_surface_layer.getFeatures(): surface_geom = surface_feat.geometry() intersection = f_geom.intersection(surface_geom) surface_area += intersection.area() mmf.setCurrentStep(nb_steps) else: surface_area = f_area # Output result feature new_feat = QgsFeature(out_fields) new_feat.setGeometry(feat.geometry()) for report_field in reporting_fields: new_feat[report_field] = feat[report_field] new_feat[self.NB_LAMPS] = nb_lamps new_feat[self.FLUX_SUM] = flux_sum new_feat[self.SURFACE_AREA] = surface_area new_feat[ self. FLUX_DEN] = flux_sum / surface_area if surface_area > 0 else None sink.addFeature(new_feat, QgsFeatureSink.FastInsert) except Exception as e: feedback.reportError('Unexpected error : ' + str(e)) raise e multi_feedback.setCurrentStep(current + 1) return {self.OUTPUT: self.dest_id}
class CartogramWorkOrchestratorMixIn: """Manage the tasks of the plugin’s workers.""" def __init__(self): """Manage the tasks of the plugin’s workers.""" super(CartogramWorkOrchestratorMixIn, self).__init__() self.add_processing_provider() def add_processing_provider(self): self.provider = CartogramProcessingProvider() QgsApplication.processingRegistry().addProvider(self.provider) def cancel_task(self): self.disable_cancel_button() self.task.cancel() def is_task_running(self): try: return self.task.isActive() except (AttributeError, RuntimeError): # (no self.task) return False def remove_processing_provider(self): QgsApplication.processingRegistry().removeProvider(self.provider) def sample_layer(self): source_layer = QgsVectorLayer( os.path.join(self.plugin_dir, "data", "Austria_PopulationByNUTS2.gml"), "" ) # (empty) memory layer sample_layer = QgsVectorLayer( QgsWkbTypes.geometryDisplayString(source_layer.geometryType()) + "?crs=" + source_layer.crs().authid() + "&index=yes", "Austria_Population_NUTS2_20170101", "memory" ) sample_layer_data_provider = sample_layer.dataProvider() sample_layer_data_provider.addAttributes(source_layer.fields().toList()) sample_layer.updateFields() sample_layer_data_provider.addFeatures(list(source_layer.getFeatures())) sample_layer.loadNamedStyle( os.path.join(self.plugin_dir, "data", "Austria_PopulationByNUTS2.qml") ) sample_layer.setTitle("Austria: Population by NUTS2 regions, 1 Jan 2017") sample_layer.setShortName("Austria_Population_NUTS2_20170101") sample_layer.setAbstract( "Austria’s population by NUTS2 region, as of 1 Jan 2017 \n" + "\n" + "Data sources: \n" + " http://ec.europa.eu/eurostat/web/gisco/geodata/" + "reference-data/administrative-units-statistical-units/" + "nuts#nuts13 \n" + " http://www.statistik.at/web_de/statistiken/" + "menschen_und_gesellschaft/bevoelkerung/" + "bevoelkerungsstand_und_veraenderung/" + "bevoelkerung_zu_jahres-_quartalsanfang/index.html" ) return sample_layer def start_task(self, input_layer, field, max_iterations, max_average_error): self.context = QgsProcessingContext() self.feedback = QgsProcessingFeedback() self.task = QgsProcessingAlgRunnerTask( QgsApplication.processingRegistry().algorithmById("cartogram3:compute_cartogram"), { "INPUT": input_layer, "FIELD": field, "MAX_ITERATIONS": max_iterations, "MAX_AVERAGE_ERROR": max_average_error, "OUTPUT": "memory:" }, self.context, self.feedback ) self.task.executed.connect(self.task_finished) self.feedback.progressChanged.connect(self.update_progress) QgsApplication.taskManager().addTask(self.task) def task_finished(self, successful, results={}): if successful: output_layer = self.context.getMapLayer(results["OUTPUT"]) if output_layer and output_layer.isValid(): layer = self.context.takeResultLayer(output_layer.id()) self.add_result_layer_to_map_canvas(layer, results["FIELD"]) self.feedback.pushInfo( ( "Finished computing cartogram for layer {:s} on field {:s} " + "after {:d} iterations with {:.2n}% residual error." ).format( self.input_layer.name(), results["FIELD"], results["ITERATIONS"], results["RESIDUAL_AVERAGE_ERROR"] ) ) else: if self.feedback.isCanceled(): self.feedback.pushWarning("User canceled cartogram computation") self.feedback.reportError("Failed to compute cartogram") self.clean_up_ui() # remove progress bar def update_progress(self, progress): self.update_progress_bar(progress)
def createContext(feedback=None): """ Creates a default processing context :param feedback: Optional existing QgsProcessingFeedback object, or None to use a default feedback object :type feedback: Optional[QgsProcessingFeedback] :returns: New QgsProcessingContext object :rtype: QgsProcessingContext """ context = QgsProcessingContext() context.setProject(QgsProject.instance()) context.setFeedback(feedback) invalid_features_method = ProcessingConfig.getSetting(ProcessingConfig.FILTER_INVALID_GEOMETRIES) if invalid_features_method is None: invalid_features_method = QgsFeatureRequest.GeometryAbortOnInvalid context.setInvalidGeometryCheck(invalid_features_method) settings = QgsSettings() context.setDefaultEncoding(settings.value("/Processing/encoding", "System")) context.setExpressionContext(createExpressionContext()) return context
def createContext(): """ Creates a default processing context """ context = QgsProcessingContext() context.setProject(QgsProject.instance()) invalid_features_method = ProcessingConfig.getSetting( ProcessingConfig.FILTER_INVALID_GEOMETRIES) if invalid_features_method is None: invalid_features_method = QgsFeatureRequest.GeometryAbortOnInvalid context.setInvalidGeometryCheck(invalid_features_method) def raise_error(f): raise GeoAlgorithmExecutionException( QCoreApplication.translate( "FeatureIterator", 'Features with invalid geometries found. Please fix these geometries or specify the "Ignore invalid input features" flag' )) context.setInvalidGeometryCallback(raise_error) def raise_transform_error(f): raise GeoAlgorithmExecutionException( QCoreApplication.translate( "FeatureIterator", 'Encountered a transform error when reprojecting feature with id {}.' .format(f.id()))) context.setTransformErrorCallback(raise_transform_error) settings = QgsSettings() context.setDefaultEncoding(settings.value("/Processing/encoding", "System")) return context
def testOgr2Ogr(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() source = os.path.join(testDataPath, 'polys.gml') multi_source = os.path.join(testDataPath, 'multi_layers.gml') alg = ogr2ogr() alg.initAlgorithm() with tempfile.TemporaryDirectory() as outdir: self.assertEqual( alg.getConsoleCommands( { 'INPUT': source, 'OUTPUT': outdir + '/check.shp' }, context, feedback), [ 'ogr2ogr', '-f "ESRI Shapefile" ' + outdir + '/check.shp ' + source + ' polys2' ]) self.assertEqual( alg.getConsoleCommands( { 'INPUT': source, 'OUTPUT': outdir + '/check.kml' }, context, feedback), [ 'ogr2ogr', '-f "LIBKML" ' + outdir + '/check.kml ' + source + ' polys2' ]) self.assertEqual( alg.getConsoleCommands( { 'INPUT': source, 'OUTPUT': outdir + '/my out/check.kml' }, context, feedback), [ 'ogr2ogr', '-f "LIBKML" "' + outdir + '/my out/check.kml" ' + source + ' polys2' ]) self.assertEqual( alg.getConsoleCommands( { 'INPUT': source, 'OUTPUT': outdir + '/check.gpkg' }, context, feedback), [ 'ogr2ogr', '-f "GPKG" ' + outdir + '/check.gpkg ' + source + ' polys2' ]) self.assertEqual( alg.getConsoleCommands( { 'INPUT': multi_source + '|layername=lines', 'CONVERT_ALL_LAYERS': False, 'OUTPUT': outdir + '/check.gpkg' }, context, feedback), [ 'ogr2ogr', '-f "GPKG" ' + outdir + '/check.gpkg ' + multi_source + ' lines' ]) self.assertEqual( alg.getConsoleCommands( { 'INPUT': multi_source + '|layername=lines', 'CONVERT_ALL_LAYERS': True, 'OUTPUT': outdir + '/check.gpkg' }, context, feedback), [ 'ogr2ogr', '-f "GPKG" ' + outdir + '/check.gpkg ' + multi_source ])
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ source_pts = self.parameterAsSource(parameters, self.INPUT_POINTS, context) input_field = self.parameterAsString(parameters, self.INPUT_FIELD, context) source_dem = self.parameterAsRasterLayer(parameters, self.INPUT_DEM, context) out_directory = self.parameterAsString(parameters, self.OUTPUT_DIR, context) out_type_nr = self.parameterAsInt(parameters, self.OUTPUT_TYPE, context) out_type = QgsVectorFileWriter.supportedFormatExtensions( )[:2][out_type_nr] to_gpkg = out_type == 'gpkg' load_results = self.parameterAsBool(parameters, self.LOAD_RESULTS, context) if source_pts is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT_POINTS)) if source_dem is None: raise QgsProcessingException( self.invalidSourceError(parameters, self.INPUT_DEM)) feedback.pushInfo("Input data loaded! Creating catchments...") feedback.setProgress(1) unique_field = input_field if input_field else "" if unique_field: field_idx = source_pts.fields().lookupField(unique_field) unique_values = source_pts.uniqueValues(field_idx) else: unique_values = [f.id() for f in source_pts.getFeatures()] feedback.pushInfo(f"Creating directory: {out_directory}") mkdir(out_directory) bname = f"catchment{'s' if to_gpkg else ''}" output_basename = os.path.join(out_directory, bname) # Compute the number of steps to display within the progress bar and # get features from source total_nr = len(unique_values) total = 100. / total_nr if source_pts.featureCount() else 1 output_layers = [] for i, unique_value in enumerate(unique_values): # Stop the algorithm if cancel button has been clicked if feedback.isCanceled(): break table = f"catchment_{unique_value}" if to_gpkg else "" file_mod = "" if to_gpkg else f"_{unique_value}" filename = f"{output_basename}{file_mod}" destination = f"{filename}.{out_type}" output_uri = destination + (f"|layername={table}" if to_gpkg else "") feedback.pushInfo( self.tr('Creating layer: {}').format(destination)) if unique_field: req_filter = f"{QgsExpression.quotedColumnRef(unique_field)}={QgsExpression.quotedValue(unique_value)}" req = QgsFeatureRequest().setFilterExpression(req_filter) else: req = QgsFeatureRequest(unique_value) # feature id for source_pt in source_pts.getFeatures(req): if feedback.isCanceled(): break # Get x and y coordinate from point feature geom = source_pt.geometry() p = geom.asPoint() x = p.x() y = p.y() feedback.pushInfo( 'Creating upslope area for point ({:.2f}, {:.2f}) - {} of {}' .format(x, y, i + 1, total_nr)) # Calculate catchment raster from point feature catchraster = processing.run( "saga:upslopearea", { 'TARGET': None, 'TARGET_PT_X': x, 'TARGET_PT_Y': y, 'ELEVATION': source_dem, 'SINKROUTE': None, 'METHOD': 0, 'CONVERGE': 1.1, 'AREA': 'TEMPORARY_OUTPUT' }, context=context, feedback=feedback, ) # Polygonize raster catchment catchpoly = processing.run( "gdal:polygonize", { 'INPUT': catchraster["AREA"], 'BAND': 1, 'FIELD': 'DN', 'EIGHT_CONNECTEDNESS': False, 'OUTPUT': 'TEMPORARY_OUTPUT' }, context=context, feedback=feedback, ) # Select features having DN = 100 catchpoly_lyr = QgsProcessingUtils.mapLayerFromString( catchpoly["OUTPUT"], context=context) catchpoly_lyr.selectByExpression('"DN"=100') options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = "GPKG" if to_gpkg else "ESRI Shapefile" options.layerName = table options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer options.onlySelectedFeatures = True trans_context = QgsCoordinateTransformContext() write_result, error_message = QgsVectorFileWriter.writeAsVectorFormatV2( catchpoly_lyr, destination, trans_context, options) if write_result != 0: feedback.pushInfo(f"Initial write failed: {error_message}") # retry with option for creating the dataset options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteFile write_result, error_message = QgsVectorFileWriter.writeAsVectorFormatV2( catchpoly_lyr, destination, trans_context, options) feedback.pushInfo( f"Final write attempt: {write_result} == 0 -> SUCCESS or {error_message}" ) output_layer = QgsProcessingUtils.mapLayerFromString( output_uri, context=context) output_layers.append(output_uri) if load_results: context.temporaryLayerStore().addMapLayer(output_layer) context.addLayerToLoadOnCompletion( output_layer.id(), QgsProcessingContext.LayerDetails( table if to_gpkg else f"catchment {unique_value}", context.project(), self.OUTPUT_LAYERS)) feedback.setProgress(int((i + 1) * total)) return { self.OUTPUT_DIR: out_directory, self.OUTPUT_LAYERS: output_layers }
def testReadOgr(self): """ Test reading vector inputs """ alg = RAlgorithm( description_file=os.path.join(test_data_path, 'test_vectorin.rsx')) alg.initAlgorithm() context = QgsProcessingContext() feedback = QgsProcessingFeedback() script = alg.build_import_commands( {'Layer': os.path.join(test_data_path, 'lines.shp')}, context, feedback) USE_NEW_API = Qgis.QGIS_VERSION_INT >= 30900 and hasattr( QgsProcessingAlgorithm, 'parameterAsCompatibleSourceLayerPathAndLayerName') if USE_NEW_API: self.assertEqual( script[0], 'Layer <- readOGR("{}")'.format( os.path.join(test_data_path, 'lines.shp'))) else: self.assertEqual( script[0], 'Layer <- readOGR("{}")'.format( os.path.join(test_data_path, 'lines.shp'))) script = alg.build_import_commands( { 'Layer': os.path.join(test_data_path, 'lines.shp').replace('/', '\\') }, context, feedback) if USE_NEW_API: self.assertEqual( script[0], 'Layer <- readOGR("{}")'.format( os.path.join(test_data_path, 'lines.shp'))) else: self.assertEqual( script[0], 'Layer <- readOGR("{}")'.format( os.path.join(test_data_path, 'lines.shp'))) vl = QgsVectorLayer( os.path.join(test_data_path, 'test_gpkg.gpkg') + '|layername=points') self.assertTrue(vl.isValid()) vl2 = QgsVectorLayer( os.path.join(test_data_path, 'test_gpkg.gpkg') + '|layername=lines') self.assertTrue(vl2.isValid()) script = alg.build_import_commands({ 'Layer': vl, 'Layer2': vl2 }, context, feedback) if USE_NEW_API: # use the newer api and avoid unnecessary layer translation self.assertEqual(script, [ 'Layer <- readOGR("{}", layer="points")'.format( os.path.join(test_data_path, 'test_gpkg.gpkg')), 'Layer2 <- readOGR("{}", layer="lines")'.format( os.path.join(test_data_path, 'test_gpkg.gpkg')) ]) else: # older version, forced to use inefficient api self.assertIn('Layer <- readOGR("/tmp', script[0]) self.assertIn('Layer2 <- readOGR("/tmp', script[1])
def processAlgorithm(self, parameters, context, feedback): # Init ORS client providers = configmanager.read_config()['providers'] provider = providers[self.parameterAsEnum(parameters, self.IN_PROVIDER, context)] clnt = client.Client(provider) clnt.overQueryLimit.connect( lambda: feedback.reportError("OverQueryLimit: Retrying...")) params = dict() geometry_param = self.GEOMETRY_TYPES[self.parameterAsEnum( parameters, self.IN_GEOMETRY, context)] params[ self.IN_GEOMETRY] = True if geometry_param == 'Polygon' else False mode = self.MODE_TYPES[self.parameterAsEnum(parameters, self.IN_MODE, context)] source = self.parameterAsSource(parameters, self.IN_POINTS, context) if source.wkbType() == 4: raise QgsProcessingException( "TypeError: Multipoint Layers are not accepted. Please convert to single geometry layer." ) # Get ID field properties id_field_name = self.parameterAsString(parameters, self.IN_FIELD, context) id_field_id = source.fields().lookupField(id_field_name) if id_field_name == '': id_field_id = 0 id_field_name = source.fields().field(id_field_id).name() id_field = source.fields().field(id_field_id) # Populate iso_layer instance with parameters self.isochrones.set_parameters(self.PROFILE, geometry_param, id_field.type(), id_field_name) layer_time = QgsVectorLayer(f'{geometry_param}?crs=EPSG:4326', f'Isochrones {self.PROFILE.capitalize()}', 'memory') self.isos_time_id = layer_time.id() layer_time_pr = layer_time.dataProvider() layer_time_pr.addAttributes(self.isochrones.get_fields()) layer_time.updateFields() layer_dist = QgsVectorLayer( f'{geometry_param}?crs=EPSG:4326', f'Isodistances {self.PROFILE.capitalize()}', 'memory') self.isos_dist_id = layer_dist.id() layer_dist_pr = layer_dist.dataProvider() layer_dist_pr.addAttributes(self.isochrones.get_fields()) layer_dist.updateFields() layer_snapped_points = QgsVectorLayer( f'MultiPoint?crs=EPSG:4326', f'Snapped Points {self.PROFILE.capitalize()}', 'memory') self.points_snapped_id = layer_snapped_points.id() layer_snapped_points_pr = layer_snapped_points.dataProvider() layer_snapped_points_pr.addAttributes( self.isochrones.get_point_fields()) layer_snapped_points.updateFields() layer_input_points = QgsVectorLayer( f'Point?crs=EPSG:4326', f'Input Points {self.PROFILE.capitalize()}', 'memory') self.points_input_id = layer_input_points.id() layer_input_points_pr = layer_input_points.dataProvider() layer_input_points_pr.addAttributes(self.isochrones.get_point_fields()) layer_input_points.updateFields() denoise = self.parameterAsDouble(parameters, self.IN_DENOISE, context) if denoise: params[self.IN_DENOISE] = denoise generalize = self.parameterAsDouble(parameters, self.IN_GENERALIZE, context) if generalize: params[self.IN_GENERALIZE] = generalize avoid_layer = self.parameterAsLayer(parameters, self.IN_AVOID, context) if avoid_layer: params['avoid_locations'] = get_avoid_locations(avoid_layer) show_locations = self.parameterAsBool(parameters, self.IN_SHOW_LOCATIONS, context) # Sets all advanced parameters as attributes of self.costing_options self.costing_options.set_costing_options(self, parameters, context) intervals_time = self.parameterAsString(parameters, self.IN_INTERVALS_TIME, context) intervals_distance = self.parameterAsString(parameters, self.IN_INTERVALS_DISTANCE, context) feat_count = source.featureCount( ) if not intervals_time else source.featureCount() * 2 self.intervals = { "time": [{ "time": int(x) } for x in intervals_time.split(',')] if intervals_time else [], "distance": [{ "distance": int(x) } for x in intervals_distance.split(',')] if intervals_distance else [] } counter = 0 for metric, interv in self.intervals.items(): if feedback.isCanceled(): break if not interv: continue # Make the actual requests requests = [] for properties in self.get_sorted_feature_parameters(source): if feedback.isCanceled(): break r_params = deepcopy(params) r_params['contours'] = interv # Get transformed coordinates and feature locations, feat = properties r_params.update( get_directions_params(locations, self.PROFILE, self.costing_options, mode)) r_params['id'] = feat[id_field_name] requests.append(r_params) for params in requests: counter += 1 if feedback.isCanceled(): break # If feature causes error, report and continue with next try: # Populate features from response response = clnt.request('/isochrone', post_json=params) except (exceptions.ApiError) as e: msg = "Feature ID {} caused a {}:\n{}".format( params['id'], e.__class__.__name__, str(e)) feedback.reportError(msg) logger.log(msg, 2) continue except (exceptions.InvalidKey, exceptions.GenericServerError) as e: msg = "{}:\n{}".format(e.__class__.__name__, str(e)) feedback.reportError(msg) logger.log(msg) raise options = {} if params.get('costing_options'): options = params['costing_options'] self.isochrones.set_response(response) for isochrone in self.isochrones.get_features( params['id'], options.get(self.PROFILE)): if metric == 'time': layer_time_pr.addFeature(isochrone) elif metric == 'distance': layer_dist_pr.addFeature(isochrone) if show_locations: for point_feat in self.isochrones.get_multipoint_features( params['id']): layer_snapped_points_pr.addFeature(point_feat) for point_feat in self.isochrones.get_point_features( params['id']): layer_input_points_pr.addFeature(point_feat) feedback.setProgress(int((counter / feat_count) * 100)) temp = [] if layer_time.hasFeatures(): layer_time.updateExtents() context.temporaryLayerStore().addMapLayer(layer_time) temp.append( ("Isochrones " + self.PROFILE.capitalize(), self.OUT_TIME, layer_time.id())) if layer_dist.hasFeatures(): layer_dist.updateExtents() context.temporaryLayerStore().addMapLayer(layer_dist) temp.append( ("Isochrones " + self.PROFILE.capitalize(), self.OUT_DISTANCE, layer_dist.id())) if show_locations: layer_snapped_points.updateExtents() context.temporaryLayerStore().addMapLayer(layer_snapped_points) temp.append(("Snapped Points " + self.PROFILE.capitalize(), self.POINTS_SNAPPED, layer_snapped_points.id())) layer_input_points.updateExtents() context.temporaryLayerStore().addMapLayer(layer_input_points) temp.append(("Input Points " + self.PROFILE.capitalize(), self.POINTS_INPUT, layer_input_points.id())) results = dict() for l_name, e_id, l_id in temp: results[e_id] = l_id context.addLayerToLoadOnCompletion( l_id, QgsProcessingContext.LayerDetails(l_name, context.project(), l_name)) return results
def createContext(feedback=None): """ Creates a default processing context :param feedback: Optional existing QgsProcessingFeedback object, or None to use a default feedback object :type feedback: Optional[QgsProcessingFeedback] :returns: New QgsProcessingContext object :rtype: QgsProcessingContext """ context = QgsProcessingContext() context.setProject(QgsProject.instance()) context.setFeedback(feedback) invalid_features_method = ProcessingConfig.getSetting( ProcessingConfig.FILTER_INVALID_GEOMETRIES) if invalid_features_method is None: invalid_features_method = QgsFeatureRequest.GeometryAbortOnInvalid context.setInvalidGeometryCheck(invalid_features_method) settings = QgsSettings() context.setDefaultEncoding(settings.value("/Processing/encoding", "System")) context.setExpressionContext(createExpressionContext()) return context
def createContext(): """ Creates a default processing context """ context = QgsProcessingContext() context.setProject(QgsProject.instance()) use_selection = ProcessingConfig.getSetting(ProcessingConfig.USE_SELECTED) if use_selection: context.setFlags(QgsProcessingContext.UseSelectionIfPresent) invalid_features_method = ProcessingConfig.getSetting(ProcessingConfig.FILTER_INVALID_GEOMETRIES) if not invalid_features_method: invalid_features_method = QgsFeatureRequest.GeometryAbortOnInvalid context.setInvalidGeometryCheck(invalid_features_method) def raise_error(f): raise GeoAlgorithmExecutionException(QCoreApplication.translate("FeatureIterator", 'Features with invalid geometries found. Please fix these geometries or specify the "Ignore invalid input features" flag')) context.setInvalidGeometryCallback(raise_error) settings = QgsSettings() context.setDefaultEncoding(settings.value("/Processing/encoding", "System")) return context
def testOgr2PostGis(self): context = QgsProcessingContext() feedback = QgsProcessingFeedback() source = os.path.join(testDataPath, 'polys.gml') source_with_space = os.path.join(testDataPath, 'filename with spaces.gml') alg = OgrToPostGis() alg.initAlgorithm() self.assertEqual( alg.getConsoleCommands({'INPUT': source}, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({'INPUT': source_with_space}, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 "' + source_with_space + '" filename_with_spaces ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.filename_with_spaces -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'HOST': 'google.com' }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=google.com port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'PORT': 3333 }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=3333 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'USER': '******' }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public user=kevin_bacon" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'DBNAME': 'secret_stuff' }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 dbname=secret_stuff active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'PASSWORD': '******' }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 password=passw0rd active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'SCHEMA': 'desktop' }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=desktop" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln desktop.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'TABLE': 'out_table' }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.out_table -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'PK': '' }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'PK': 'new_fid' }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=new_fid -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands( { 'INPUT': source, 'PK': '', 'PRIMARY_KEY': 'objectid' }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=objectid -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands( { 'INPUT': source, 'PK': 'new_id', 'PRIMARY_KEY': 'objectid' }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=new_id -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'GEOCOLUMN': 'my_geom' }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=my_geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'DIM': 1 }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=3 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'SIMPLIFY': 5 }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -simplify 5 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'SEGMENTIZE': 4 }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -segmentize 4 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands( { 'INPUT': source, 'SPAT': QgsRectangle(1, 2, 3, 4) }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -spat 1.0 2.0 3.0 4.0 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'FIELDS': ['f1', 'f2'] }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 -select "f1,f2" ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'WHERE': '0=1' }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -where "0=1" -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'GT': 2 }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -gt 2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'OVERWRITE': False }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'APPEND': True }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-append -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'ADDFIELDS': True }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-addfields -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'LAUNDER': True }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-lco LAUNDER=NO -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'INDEX': True }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-lco SPATIAL_INDEX=OFF -overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'SKIPFAILURES': True }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -skipfailures -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'PROMOTETOMULTI': False }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'PRECISION': False }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI -lco PRECISION=NO' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'OPTIONS': 'blah' }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI blah' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'SHAPE_ENCODING': 'blah' }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES --config SHAPE_ENCODING blah -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'GTYPE': 4 }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -nlt LINESTRING -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'A_SRS': 'EPSG:3111' }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands( { 'INPUT': source, 'A_SRS': QgsCoordinateReferenceSystem('EPSG:3111') }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:3111 -nlt PROMOTE_TO_MULTI' ]) custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs' self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'A_SRS': custom_crs }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -a_srs EPSG:20936 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'T_SRS': 'EPSG:3111' }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:3111 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands( { 'INPUT': source, 'T_SRS': QgsCoordinateReferenceSystem('EPSG:3111') }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:3111 -nlt PROMOTE_TO_MULTI' ]) custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs' self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'T_SRS': custom_crs }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -t_srs EPSG:20936 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'S_SRS': 'EPSG:3111' }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:3111 -nlt PROMOTE_TO_MULTI' ]) self.assertEqual( alg.getConsoleCommands( { 'INPUT': source, 'S_SRS': QgsCoordinateReferenceSystem('EPSG:3111') }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:3111 -nlt PROMOTE_TO_MULTI' ]) custom_crs = 'proj4: +proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs' self.assertEqual( alg.getConsoleCommands({ 'INPUT': source, 'S_SRS': custom_crs }, context, feedback), [ 'ogr2ogr', '-progress --config PG_USE_COPY YES -f PostgreSQL "PG:host=localhost port=5432 active_schema=public" ' '-lco DIM=2 ' + source + ' polys2 ' '-overwrite -lco GEOMETRY_NAME=geom -lco FID=id -nln public.polys2 -s_srs EPSG:20936 -nlt PROMOTE_TO_MULTI' ])
def __init__(self, parent: QWidget = None) -> None: QDialog.__init__(self, parent) self.setupUi(self) self.message_bar: QgsMessageBar self.btn_load.clicked.connect(self.__load_wfs_layer) self.btn_select.clicked.connect(self.__select_wfs_layer) self.btn_clear_search.clicked.connect( self.__clear_stored_wfs_queries_search) # Typing self.extent_group_box_bbox: QgsExtentGroupBox self.progress_bar: QProgressBar self.search_ln_ed: QgsFilterLineEdit self.search_ln_ed.valueChanged.connect(self.__search_stored_wfs_layers) self.extent_group_box_bbox.setOriginalExtent( iface.mapCanvas().extent(), iface.mapCanvas().mapSettings().destinationCrs(), ) self.extent_group_box_bbox.setCurrentExtent( iface.mapCanvas().extent(), iface.mapCanvas().mapSettings().destinationCrs(), ) self.extent_group_box_bbox.setOutputCrs( QgsCoordinateReferenceSystem("EPSG:4326")) try: self.extent_group_box_bbox.setMapCanvas(iface.mapCanvas(), drawOnCanvasOption=False) except TypeError: self.extent_group_box_bbox.setMapCanvas(iface.mapCanvas()) self.extent_group_box_bbox.setOutputExtentFromCurrent() self.chk_box_add_to_map: QCheckBox self.btn_output_dir_select: QgsFileWidget self.btn_output_dir_select.setFilePath( str( Path(QgsProject.absoluteFilePath( QgsProject.instance())).parent)) self.progress_bar.setValue(0) # Context and feedback for processing algorithms self.context: QgsProcessingContext = QgsProcessingContext() self.feedback: QgsProcessingFeedback = LoggerProcessingFeedBack( use_logger=True) self.responsive_items = { self.btn_load, self.btn_select, self.chk_box_add_to_map, self.btn_clear_search, } self.task: Optional[BaseLoader] = None self.sq_factory = StoredQueryFactory(Settings.FMI_WFS_URL.get(), Settings.FMI_WFS_VERSION.get()) self.stored_queries: List[StoredQuery] = [] self.selected_stored_query: Optional[StoredQuery] = None # populating dynamically the parameters of main dialog self.grid: QGridLayout self.parameter_rows: Dict[str, Set[QWidget]] = {} self.tbl_wdgt_stored_queries: QTableWidget # populating the layer list when opening self.__refresh_stored_wfs_queries()
def createContext(feedback=None): """ Creates a default processing context """ context = QgsProcessingContext() context.setProject(QgsProject.instance()) context.setFeedback(feedback) invalid_features_method = ProcessingConfig.getSetting(ProcessingConfig.FILTER_INVALID_GEOMETRIES) if invalid_features_method is None: invalid_features_method = QgsFeatureRequest.GeometryAbortOnInvalid context.setInvalidGeometryCheck(invalid_features_method) settings = QgsSettings() context.setDefaultEncoding(settings.value("/Processing/encoding", "System")) context.setExpressionContext(createExpressionContext()) return context
def testInPlace(self): geocoder = TestGeocoderExtraFields() alg = TestGeocoderAlgorithm(geocoder) alg.initParameters({'IN_PLACE': True}) fields = QgsFields() fields.append(QgsField('some_pk', QVariant.Int)) fields.append(QgsField('address', QVariant.String)) fields.append(QgsField('parsedx', QVariant.String)) fields.append(QgsField('accuracyx', QVariant.Int)) output_fields = alg.outputFields(fields) self.assertEqual([f.name() for f in output_fields], ['some_pk', 'address', 'parsedx', 'accuracyx']) self.assertEqual( [f.type() for f in output_fields], [QVariant.Int, QVariant.String, QVariant.String, QVariant.Int]) f = QgsFeature(fields) f.initAttributes(4) f['some_pk'] = 17 # not storing additional attributes params = {'FIELD': 'address'} context = QgsProcessingContext() feedback = QgsProcessingFeedback() self.assertTrue(alg.prepareAlgorithm(params, context, feedback)) # empty field res = alg.processFeature(f, context, feedback) self.assertEqual(len(res), 1) self.assertTrue(res[0].geometry().isNull()) self.assertEqual(res[0].attributes(), [17, NULL, NULL, NULL]) f['address'] = 'a' res = alg.processFeature(f, context, feedback) self.assertEqual(len(res), 1) self.assertEqual(res[0].geometry().asWkt(), 'Point (1 2)') self.assertEqual(res[0].attributes(), [17, 'a', None, None]) f.clearGeometry() f['address'] = NULL # storing additional attributes params = { 'FIELD': 'address', 'parsed': 'parsedx', 'accuracy': 'accuracyx' } context = QgsProcessingContext() feedback = QgsProcessingFeedback() self.assertTrue(alg.prepareAlgorithm(params, context, feedback)) # empty field res = alg.processFeature(f, context, feedback) self.assertEqual(len(res), 1) self.assertTrue(res[0].geometry().isNull()) self.assertEqual(res[0].attributes(), [17, NULL, NULL, NULL]) f['address'] = 'b' res = alg.processFeature(f, context, feedback) self.assertEqual(len(res), 1) self.assertEqual(res[0].geometry().asWkt(), 'Point (11 12)') self.assertEqual(res[0].attributes(), [17, 'b', 'xyz2', 456])
def test_flags(self): """ Test task flags """ thread_safe_alg = QgsApplication.processingRegistry().algorithmById( 'native:buffer') nonthread_safe_alg = QgsApplication.processingRegistry().algorithmById( 'native:setprojectvariable') context = QgsProcessingContext() context.setProject(QgsProject.instance()) feedback = ConsoleFeedBack() task = QgsProcessingAlgRunnerTask(thread_safe_alg, {}, context=context, feedback=feedback) self.assertEqual(task.flags(), QgsTask.CanCancel) task = QgsProcessingAlgRunnerTask(thread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.Flags()) self.assertEqual(task.flags(), QgsTask.Flags()) task = QgsProcessingAlgRunnerTask(thread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.CanCancel) self.assertEqual(task.flags(), QgsTask.CanCancel) task = QgsProcessingAlgRunnerTask(thread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.CancelWithoutPrompt) self.assertEqual(task.flags(), QgsTask.CancelWithoutPrompt) task = QgsProcessingAlgRunnerTask(thread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.CancelWithoutPrompt | QgsTask.CanCancel) self.assertEqual(task.flags(), QgsTask.CancelWithoutPrompt | QgsTask.CanCancel) # alg which can't be canceled task = QgsProcessingAlgRunnerTask(nonthread_safe_alg, {}, context=context, feedback=feedback) self.assertEqual(task.flags(), QgsTask.Flags()) # we clear the CanCancel flag automatically, since the algorithm itself cannot be canceled task = QgsProcessingAlgRunnerTask(nonthread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.CanCancel) self.assertEqual(task.flags(), QgsTask.Flags()) # hidden task task = QgsProcessingAlgRunnerTask(thread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.Hidden) self.assertEqual(task.flags(), QgsTask.Hidden) task = QgsProcessingAlgRunnerTask(thread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.Hidden | QgsTask.CanCancel) self.assertEqual(task.flags(), QgsTask.Hidden | QgsTask.CanCancel) task = QgsProcessingAlgRunnerTask(thread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.Hidden | QgsTask.CanCancel | QgsTask.CancelWithoutPrompt) self.assertEqual( task.flags(), QgsTask.Hidden | QgsTask.CanCancel | QgsTask.CancelWithoutPrompt) task = QgsProcessingAlgRunnerTask(nonthread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.Hidden) self.assertEqual(task.flags(), QgsTask.Hidden) task = QgsProcessingAlgRunnerTask(nonthread_safe_alg, {}, context=context, feedback=feedback, flags=QgsTask.Hidden | QgsTask.CanCancel) self.assertEqual(task.flags(), QgsTask.Hidden)
def processAlgorithm(self, parameters, context, feedback): """ Here is where the processing itself takes place. """ source = self.parameterAsSource(parameters, self.INPUT, context) path = self.parameterAsFile(parameters, self.OUTPUT, context) field_def = { 'idx': QVariant.Int, 'name': QVariant.String, 'type': QVariant.Int, 'typeName': QVariant.String, 'length': QVariant.Int, 'precision': QVariant.Int, 'comment': QVariant.String, 'alias': QVariant.String } # create virtual layer vl = QgsVectorLayer("None", "fields", "memory") pr = vl.dataProvider() # define fields fields = QgsFields() for n, t in field_def.items(): fields.append(QgsField(name=n, type=t)) # add fields pr.addAttributes(fields) vl.updateFields( ) # tell the vector layer to fetch changes from the provider # add feature based on field description field_index = 0 for f in providerFields(source.fields()): field_index += 1 feat = QgsFeature() feat.setAttributes([ field_index, f.name(), f.type(), f.typeName(), f.length(), f.precision(), f.comment(), f.alias() ]) pr.addFeatures([feat]) # set create file layer options options = QgsVectorFileWriter.SaveVectorOptions() options.driverName = QgsVectorFileWriter.driverForExtension('csv') options.fileEncoding = 'UTF-8' options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteFile options.layerOptions = ['CREATE_CSVT=YES'] # write file write_result, error_message = QgsVectorFileWriter.writeAsVectorFormat( vl, path, options) # result if write_result != QgsVectorFileWriter.NoError: raise QgsProcessingException( self.tr('* ERROR: {0}').format(error_message)) del fields del pr del vl # create layer dest_layer = QgsVectorLayer(path, self.OUTPUT_LAYER, 'ogr') if not dest_layer.isValid(): raise QgsProcessingException( self.tr('* ERROR: Can\'t load layer {1} in {0}').format( path, self.OUTPUT_LAYER)) # Add layer to context context.temporaryLayerStore().addMapLayer(dest_layer) context.addLayerToLoadOnCompletion( dest_layer.id(), QgsProcessingContext.LayerDetails(self.OUTPUT_LAYER, context.project(), self.OUTPUT_LAYER)) return {self.OUTPUT: path, self.OUTPUT_LAYER: dest_layer.id()}