mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
[processing][GRASS] Correctly handle input vector layers with |layername= param
Fixes #20277
This commit is contained in:
parent
82ac04d6f7
commit
f65c845f86
@ -62,7 +62,8 @@ from qgis.core import (Qgis,
|
||||
QgsProcessingParameterFolderDestination,
|
||||
QgsProcessingOutputHtml,
|
||||
QgsProcessingUtils,
|
||||
QgsVectorLayer)
|
||||
QgsVectorLayer,
|
||||
QgsProviderRegistry)
|
||||
from qgis.utils import iface
|
||||
from osgeo import ogr
|
||||
|
||||
@ -110,12 +111,15 @@ class Grass7Algorithm(QgsProcessingAlgorithm):
|
||||
self.params = []
|
||||
self.hardcodedStrings = []
|
||||
self.inputLayers = []
|
||||
self.commands = []
|
||||
self.outputCommands = []
|
||||
self.exportedLayers = {}
|
||||
self.descriptionFile = descriptionfile
|
||||
|
||||
# Default GRASS parameters
|
||||
self.region = None
|
||||
self.cellSize = None
|
||||
self.snaptTolerance = None
|
||||
self.snapTolerance = None
|
||||
self.outputType = None
|
||||
self.minArea = None
|
||||
self.alignToResolution = None
|
||||
@ -801,7 +805,18 @@ class Grass7Algorithm(QgsProcessingAlgorithm):
|
||||
:param external: use v.external (v.in.ogr if False).
|
||||
"""
|
||||
layer = self.parameterAsVectorLayer(parameters, name, context)
|
||||
if layer is None or layer.dataProvider().name() != 'ogr':
|
||||
|
||||
is_ogr_disk_based_layer = layer is not None and layer.dataProvider().name() == 'ogr'
|
||||
if is_ogr_disk_based_layer:
|
||||
# we only support direct reading of disk based ogr layers -- not ogr postgres layers, etc
|
||||
source_parts = QgsProviderRegistry.instance().decodeUri('ogr', layer.source())
|
||||
if not source_parts.get('path'):
|
||||
is_ogr_disk_based_layer = False
|
||||
elif source_parts.get('layerId'):
|
||||
# no support for directly reading layers by id in grass
|
||||
is_ogr_disk_based_layer = False
|
||||
|
||||
if not is_ogr_disk_based_layer:
|
||||
# parameter is not a vector layer or not an OGR layer - try to convert to a source compatible with
|
||||
# grass OGR inputs and extract selection if required
|
||||
path = self.parameterAsCompatibleSourceLayerPath(parameters, name, context,
|
||||
@ -827,28 +842,36 @@ class Grass7Algorithm(QgsProcessingAlgorithm):
|
||||
external = ProcessingConfig.getSetting(
|
||||
Grass7Utils.GRASS_USE_VEXTERNAL)
|
||||
|
||||
source_parts = QgsProviderRegistry.instance().decodeUri('ogr', layer.source())
|
||||
file_path = source_parts.get('path')
|
||||
layer_name = source_parts.get('layerName')
|
||||
|
||||
# safety check: we can only use external for ogr layers which support random read
|
||||
if external:
|
||||
feedback.pushInfo('Attempting to use v.external for direct layer read')
|
||||
if feedback is not None:
|
||||
feedback.pushInfo('Attempting to use v.external for direct layer read')
|
||||
ds = ogr.Open(file_path)
|
||||
if ds is not None:
|
||||
ogr_layer = ds.GetLayer()
|
||||
if ogr_layer is None or not ogr_layer.TestCapability(ogr.OLCRandomRead):
|
||||
feedback.reportError('Cannot use v.external: layer does not support random read')
|
||||
if feedback is not None:
|
||||
feedback.reportError('Cannot use v.external: layer does not support random read')
|
||||
external = False
|
||||
else:
|
||||
feedback.reportError('Cannot use v.external: error reading layer')
|
||||
if feedback is not None:
|
||||
feedback.reportError('Cannot use v.external: error reading layer')
|
||||
external = False
|
||||
|
||||
self.inputLayers.append(layer)
|
||||
self.setSessionProjectionFromLayer(layer)
|
||||
destFilename = 'vector_{}'.format(os.path.basename(getTempFilename()))
|
||||
self.exportedLayers[name] = destFilename
|
||||
command = '{0}{1}{2} input="{3}" output="{4}" --overwrite -o'.format(
|
||||
command = '{0}{1}{2} input="{3}"{4} output="{5}" --overwrite -o'.format(
|
||||
'v.external' if external else 'v.in.ogr',
|
||||
' min_area={}'.format(self.minArea) if not external else '',
|
||||
' snap={}'.format(self.snapTolerance) if not external else '',
|
||||
os.path.normpath(layer.source()),
|
||||
os.path.normpath(file_path),
|
||||
' layer="{}"'.format(layer_name) if layer_name else '',
|
||||
destFilename)
|
||||
self.commands.append(command)
|
||||
|
||||
|
@ -31,6 +31,7 @@ import nose2
|
||||
import shutil
|
||||
import os
|
||||
import tempfile
|
||||
import re
|
||||
|
||||
from qgis.core import (QgsVectorLayer,
|
||||
QgsApplication,
|
||||
@ -48,6 +49,9 @@ from qgis.testing import (
|
||||
from processing.algs.grass7.Grass7Utils import Grass7Utils
|
||||
|
||||
|
||||
testDataPath = os.path.join(os.path.dirname(__file__), 'testdata')
|
||||
|
||||
|
||||
class TestGrass7AlgorithmsVectorTest(unittest.TestCase, AlgorithmsTestBase.AlgorithmsTest):
|
||||
|
||||
@classmethod
|
||||
@ -241,6 +245,65 @@ class TestGrass7AlgorithmsVectorTest(unittest.TestCase, AlgorithmsTestBase.Algor
|
||||
|
||||
QgsProject.instance().removeMapLayer(layer)
|
||||
|
||||
def testVectorLayerInput(self):
|
||||
alg = QgsApplication.processingRegistry().createAlgorithmById('grass7:v.buffer')
|
||||
self.assertIsNotNone(alg)
|
||||
self.assertFalse(alg.commands)
|
||||
|
||||
def get_command(alg):
|
||||
command = alg.commands[-1]
|
||||
command = re.sub(r'output=".*?"', 'output="###"', command)
|
||||
command = command.replace(testDataPath, 'testdata')
|
||||
return command
|
||||
|
||||
# GML source
|
||||
source = os.path.join(testDataPath, 'points.gml')
|
||||
vl = QgsVectorLayer(source)
|
||||
self.assertTrue(vl.isValid())
|
||||
alg.loadVectorLayer('test_layer', vl, external=False)
|
||||
self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/points.gml" output="###" --overwrite -o')
|
||||
# try with external -- not support for GML, so should fall back to v.in.ogr
|
||||
alg.loadVectorLayer('test_layer', vl, external=True)
|
||||
self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/points.gml" output="###" --overwrite -o')
|
||||
|
||||
# SHP source
|
||||
source = os.path.join(testDataPath, 'lines_z.shp')
|
||||
vl = QgsVectorLayer(source)
|
||||
self.assertTrue(vl.isValid())
|
||||
alg.loadVectorLayer('test_layer', vl, external=False)
|
||||
self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/lines_z.shp" output="###" --overwrite -o')
|
||||
# try with external -- should work for shapefile
|
||||
alg.loadVectorLayer('test_layer', vl, external=True)
|
||||
self.assertEqual(get_command(alg), 'v.external input="testdata/lines_z.shp" output="###" --overwrite -o')
|
||||
|
||||
# GPKG source
|
||||
source = os.path.join(testDataPath, 'custom/pol.gpkg')
|
||||
vl = QgsVectorLayer(source + '|layername=pol2')
|
||||
self.assertTrue(vl.isValid())
|
||||
alg.loadVectorLayer('test_layer', vl, external=False)
|
||||
self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/custom/pol.gpkg" layer="pol2" output="###" --overwrite -o')
|
||||
# try with external -- should work for Geopackage (although grass itself tends to crash here!)
|
||||
alg.loadVectorLayer('test_layer', vl, external=True)
|
||||
self.assertEqual(get_command(alg), 'v.external input="testdata/custom/pol.gpkg" layer="pol2" output="###" --overwrite -o')
|
||||
|
||||
# different layer
|
||||
source = os.path.join(testDataPath, 'custom/pol.gpkg')
|
||||
vl = QgsVectorLayer(source + '|layername=pol3')
|
||||
self.assertTrue(vl.isValid())
|
||||
alg.loadVectorLayer('test_layer', vl, external=False)
|
||||
self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/custom/pol.gpkg" layer="pol3" output="###" --overwrite -o')
|
||||
alg.loadVectorLayer('test_layer', vl, external=True)
|
||||
self.assertEqual(get_command(alg), 'v.external input="testdata/custom/pol.gpkg" layer="pol3" output="###" --overwrite -o')
|
||||
|
||||
# GPKG no layer: you get what you get and you don't get upset
|
||||
source = os.path.join(testDataPath, 'custom/pol.gpkg')
|
||||
vl = QgsVectorLayer(source)
|
||||
self.assertTrue(vl.isValid())
|
||||
alg.loadVectorLayer('test_layer', vl, external=False)
|
||||
self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/custom/pol.gpkg" output="###" --overwrite -o')
|
||||
alg.loadVectorLayer('test_layer', vl, external=True)
|
||||
self.assertEqual(get_command(alg), 'v.external input="testdata/custom/pol.gpkg" output="###" --overwrite -o')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
nose2.main()
|
||||
|
BIN
python/plugins/processing/tests/testdata/expected/grass7/buffer_polys_layer2.dbf
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/grass7/buffer_polys_layer2.dbf
vendored
Normal file
Binary file not shown.
1
python/plugins/processing/tests/testdata/expected/grass7/buffer_polys_layer2.prj
vendored
Normal file
1
python/plugins/processing/tests/testdata/expected/grass7/buffer_polys_layer2.prj
vendored
Normal file
@ -0,0 +1 @@
|
||||
PROJCS["Hotine_Oblique_Mercator_Azimuth_Center",GEOGCS["GCS_bessel",DATUM["D_unknown",SPHEROID["Bessel_1841",6377397.155,299.1528128]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Hotine_Oblique_Mercator_Azimuth_Center"],PARAMETER["latitude_of_center",46.95240555555556],PARAMETER["longitude_of_center",7.439583333333333],PARAMETER["azimuth",90],PARAMETER["scale_factor",1],PARAMETER["false_easting",2600000],PARAMETER["false_northing",1200000],UNIT["Meter",1]]
|
BIN
python/plugins/processing/tests/testdata/expected/grass7/buffer_polys_layer2.shp
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/grass7/buffer_polys_layer2.shp
vendored
Normal file
Binary file not shown.
BIN
python/plugins/processing/tests/testdata/expected/grass7/buffer_polys_layer2.shx
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/grass7/buffer_polys_layer2.shx
vendored
Normal file
Binary file not shown.
BIN
python/plugins/processing/tests/testdata/expected/grass7/buffer_polys_layer3.dbf
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/grass7/buffer_polys_layer3.dbf
vendored
Normal file
Binary file not shown.
1
python/plugins/processing/tests/testdata/expected/grass7/buffer_polys_layer3.prj
vendored
Normal file
1
python/plugins/processing/tests/testdata/expected/grass7/buffer_polys_layer3.prj
vendored
Normal file
@ -0,0 +1 @@
|
||||
PROJCS["Hotine_Oblique_Mercator_Azimuth_Center",GEOGCS["GCS_bessel",DATUM["D_unknown",SPHEROID["Bessel_1841",6377397.155,299.1528128]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Hotine_Oblique_Mercator_Azimuth_Center"],PARAMETER["latitude_of_center",46.95240555555556],PARAMETER["longitude_of_center",7.439583333333333],PARAMETER["azimuth",90],PARAMETER["scale_factor",1],PARAMETER["false_easting",2600000],PARAMETER["false_northing",1200000],UNIT["Meter",1]]
|
BIN
python/plugins/processing/tests/testdata/expected/grass7/buffer_polys_layer3.shp
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/grass7/buffer_polys_layer3.shp
vendored
Normal file
Binary file not shown.
BIN
python/plugins/processing/tests/testdata/expected/grass7/buffer_polys_layer3.shx
vendored
Normal file
BIN
python/plugins/processing/tests/testdata/expected/grass7/buffer_polys_layer3.shx
vendored
Normal file
Binary file not shown.
@ -32,6 +32,7 @@ tests:
|
||||
compare:
|
||||
geometry:
|
||||
precision: 7
|
||||
ignore_crs_check: true
|
||||
|
||||
- algorithm: grass7:v.rast.stats
|
||||
name: V.rast.stats
|
||||
@ -271,3 +272,62 @@ tests:
|
||||
raster_output:
|
||||
hash: 7aa8e68b697e1558e6621fa23b5f1f01a5826649ffc31fd255e709a1
|
||||
type: rasterhash
|
||||
|
||||
- algorithm: grass7:v.buffer
|
||||
name: Buffer with layername
|
||||
params:
|
||||
-c: false
|
||||
-s: false
|
||||
-t: false
|
||||
GRASS_MIN_AREA_PARAMETER: 0.0001
|
||||
GRASS_OUTPUT_TYPE_PARAMETER: 0
|
||||
GRASS_SNAP_TOLERANCE_PARAMETER: -1.0
|
||||
GRASS_VECTOR_DSCO: ''
|
||||
GRASS_VECTOR_LCO: ''
|
||||
angle: 0.0
|
||||
cats: ''
|
||||
distance: 10.0
|
||||
input:
|
||||
name: custom/pol.gpkg|layername=pol3
|
||||
type: vector
|
||||
scale: 1.0
|
||||
tolerance: 0.01
|
||||
type:
|
||||
- 0
|
||||
- 1
|
||||
- 4
|
||||
where: ''
|
||||
results:
|
||||
output:
|
||||
name: expected/grass7/buffer_polys_layer3.shp
|
||||
type: vector
|
||||
|
||||
- algorithm: grass7:v.buffer
|
||||
name: Buffer with layername 2
|
||||
params:
|
||||
-c: false
|
||||
-s: false
|
||||
-t: false
|
||||
GRASS_MIN_AREA_PARAMETER: 0.0001
|
||||
GRASS_OUTPUT_TYPE_PARAMETER: 0
|
||||
GRASS_SNAP_TOLERANCE_PARAMETER: -1.0
|
||||
GRASS_VECTOR_DSCO: ''
|
||||
GRASS_VECTOR_LCO: ''
|
||||
angle: 0.0
|
||||
cats: ''
|
||||
distance: 10.0
|
||||
input:
|
||||
name: custom/pol.gpkg|layername=pol2
|
||||
type: vector
|
||||
scale: 1.0
|
||||
tolerance: 0.01
|
||||
type:
|
||||
- 0
|
||||
- 1
|
||||
- 4
|
||||
where: ''
|
||||
results:
|
||||
output:
|
||||
name: expected/grass7/buffer_polys_layer2.shp
|
||||
type: vector
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user