Skip to content

Commit a675311

Browse files
committed
[processing][grass] Fix grass vector algs don't work with memory layers
Fixes broken grass algs inside models (fixes #18662) (cherry-picked from 8ba762a)
1 parent b0eb85d commit a675311

File tree

5 files changed

+203
-3
lines changed

5 files changed

+203
-3
lines changed

.ci/travis/linux/blacklist.txt

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ qgis_composermapgridtest
66
qgis_composerutils
77
ProcessingGrass7AlgorithmsImageryTest
88
ProcessingGrass7AlgorithmsRasterTest
9+
ProcessingGrass7AlgorithmsVectorTest
910
PyQgsAppStartup
1011

1112
# temporary during processing refactoring

python/plugins/processing/algs/grass7/Grass7Algorithm.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@
6060
QgsProcessingParameterFile,
6161
QgsProcessingParameterFolderDestination,
6262
QgsProcessingOutputHtml,
63-
QgsProcessingUtils)
63+
QgsProcessingUtils,
64+
QgsVectorLayer)
6465
from qgis.utils import iface
6566

6667
from processing.core.ProcessingConfig import ProcessingConfig
@@ -761,7 +762,17 @@ def loadVectorLayerFromParameter(self, name, parameters, context, feedback, exte
761762
:param external: use v.external (v.in.ogr if False).
762763
"""
763764
layer = self.parameterAsVectorLayer(parameters, name, context)
764-
self.loadVectorLayer(name, layer, external)
765+
if layer is None or layer.dataProvider().name() != 'ogr':
766+
# parameter is not a vector layer or not an OGR layer - try to convert to a source compatible with
767+
# grass OGR inputs and extract selection if required
768+
path = self.parameterAsCompatibleSourceLayerPath(parameters, name, context,
769+
QgsVectorFileWriter.supportedFormatExtensions(),
770+
feedback=feedback)
771+
ogr_layer = QgsVectorLayer(path, '', 'ogr')
772+
self.loadVectorLayer(name, ogr_layer, external)
773+
else:
774+
# already an ogr layer source
775+
self.loadVectorLayer(name, layer, external)
765776

766777
def loadVectorLayer(self, name, layer, external=False):
767778
"""
@@ -771,7 +782,6 @@ def loadVectorLayer(self, name, layer, external=False):
771782
:param layer: QgsMapLayer for the vector layer.
772783
:param external: use v.external (v.in.ogr if False).
773784
"""
774-
# TODO: support selections
775785
# TODO: support multiple input formats
776786
if external is None:
777787
external = ProcessingConfig.getSetting(

python/plugins/processing/tests/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ IF(ENABLE_TESTS)
1313
ADD_PYTHON_TEST(ProcessingGdalAlgorithmsTest GdalAlgorithmsTest.py)
1414
ADD_PYTHON_TEST(ProcessingGrass7AlgorithmsImageryTest Grass7AlgorithmsImageryTest.py)
1515
ADD_PYTHON_TEST(ProcessingGrass7AlgorithmsRasterTest Grass7AlgorithmsRasterTest.py)
16+
ADD_PYTHON_TEST(ProcessingGrass7AlgorithmsVectorTest Grass7AlgorithmsVectorTest.py)
1617
ADD_PYTHON_TEST(ProcessingSagaAlgorithmsTest SagaAlgorithmsTest.py)
1718
ENDIF(ENABLE_TESTS)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# -*- coding: utf-8 -*-
2+
3+
"""
4+
***************************************************************************
5+
Grass7AlgorithmsVectorTest.py
6+
-----------------------------
7+
Date : April 2018
8+
Copyright : (C) 2018 by Nyall Dawson
9+
Email : nyall dot dawson at gmail dot com
10+
***************************************************************************
11+
* *
12+
* This program is free software; you can redistribute it and/or modify *
13+
* it under the terms of the GNU General Public License as published by *
14+
* the Free Software Foundation; either version 2 of the License, or *
15+
* (at your option) any later version. *
16+
* *
17+
***************************************************************************
18+
"""
19+
20+
__author__ = 'Nyall Dawson'
21+
__date__ = 'March 2018'
22+
__copyright__ = '(C) 2018, Nyall Dawson'
23+
24+
# This will get replaced with a git SHA1 when you do a git archive
25+
26+
__revision__ = ':%H$'
27+
28+
import AlgorithmsTestBase
29+
30+
import nose2
31+
import shutil
32+
import os
33+
34+
from qgis.core import (QgsVectorLayer,
35+
QgsApplication,
36+
QgsFeature,
37+
QgsGeometry,
38+
QgsPointXY,
39+
QgsProcessingContext,
40+
QgsProject,
41+
QgsProcessingFeedback,
42+
QgsProcessingFeatureSourceDefinition)
43+
from qgis.testing import (
44+
start_app,
45+
unittest
46+
)
47+
from processing.algs.grass7.Grass7Utils import Grass7Utils
48+
49+
50+
class TestGrass7AlgorithmsVectorTest(unittest.TestCase, AlgorithmsTestBase.AlgorithmsTest):
51+
52+
@classmethod
53+
def setUpClass(cls):
54+
start_app()
55+
from processing.core.Processing import Processing
56+
Processing.initialize()
57+
cls.cleanup_paths = []
58+
59+
assert Grass7Utils.installedVersion()
60+
61+
@classmethod
62+
def tearDownClass(cls):
63+
from processing.core.Processing import Processing
64+
Processing.deinitialize()
65+
for path in cls.cleanup_paths:
66+
shutil.rmtree(path)
67+
68+
def test_definition_file(self):
69+
return 'grass7_algorithms_vector_tests.yaml'
70+
71+
def testMemoryLayerInput(self):
72+
# create a memory layer and add to project and context
73+
layer = QgsVectorLayer("Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer",
74+
"testmem", "memory")
75+
self.assertTrue(layer.isValid())
76+
pr = layer.dataProvider()
77+
f = QgsFeature()
78+
f.setAttributes(["test", 123])
79+
f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(100, 200)))
80+
f2 = QgsFeature()
81+
f2.setAttributes(["test2", 457])
82+
f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(110, 200)))
83+
self.assertTrue(pr.addFeatures([f, f2]))
84+
self.assertEqual(layer.featureCount(), 2)
85+
QgsProject.instance().addMapLayer(layer)
86+
context = QgsProcessingContext()
87+
context.setProject(QgsProject.instance())
88+
89+
alg = QgsApplication.processingRegistry().createAlgorithmById('grass7:v.buffer')
90+
self.assertIsNotNone(alg)
91+
temp_file = '/tmp/grass_output.shp'
92+
parameters ={'input':'testmem',
93+
'type':[0,1,4],
94+
'distance':1,
95+
'angle':0,
96+
'scale':1,
97+
'tolerance':0.01,
98+
'-s':False,
99+
'-c':False,
100+
'-t':False,
101+
'output':temp_file,
102+
'GRASS_SNAP_TOLERANCE_PARAMETER':-1,'GRASS_MIN_AREA_PARAMETER':0.0001,'GRASS_OUTPUT_TYPE_PARAMETER':0}
103+
feedback = QgsProcessingFeedback()
104+
105+
results, ok = alg.run(parameters, context, feedback)
106+
self.assertTrue(ok)
107+
self.assertTrue(os.path.exists(temp_file))
108+
109+
# make sure that layer has correct features
110+
res = QgsVectorLayer(temp_file, 'res')
111+
self.assertTrue(res.isValid())
112+
self.assertEqual(res.featureCount(), 2)
113+
114+
QgsProject.instance().removeMapLayer(layer)
115+
116+
def testFeatureSourceInput(self):
117+
# create a memory layer and add to project and context
118+
layer = QgsVectorLayer("Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer",
119+
"testmem", "memory")
120+
self.assertTrue(layer.isValid())
121+
pr = layer.dataProvider()
122+
f = QgsFeature()
123+
f.setAttributes(["test", 123])
124+
f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(100, 200)))
125+
f2 = QgsFeature()
126+
f2.setAttributes(["test2", 457])
127+
f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(110, 200)))
128+
self.assertTrue(pr.addFeatures([f, f2]))
129+
self.assertEqual(layer.featureCount(), 2)
130+
131+
# select first feature
132+
layer.selectByIds([next(layer.getFeatures()).id()])
133+
self.assertEqual(len(layer.selectedFeatureIds()), 1)
134+
135+
QgsProject.instance().addMapLayer(layer)
136+
context = QgsProcessingContext()
137+
context.setProject(QgsProject.instance())
138+
139+
alg = QgsApplication.processingRegistry().createAlgorithmById('grass7:v.buffer')
140+
self.assertIsNotNone(alg)
141+
temp_file = '/tmp/grass_output.shp'
142+
parameters = {'input': QgsProcessingFeatureSourceDefinition('testmem', True),
143+
'type': [0, 1, 4],
144+
'distance': 1,
145+
'angle': 0,
146+
'scale': 1,
147+
'tolerance': 0.01,
148+
'-s': False,
149+
'-c': False,
150+
'-t': False,
151+
'output': temp_file,
152+
'GRASS_SNAP_TOLERANCE_PARAMETER': -1, 'GRASS_MIN_AREA_PARAMETER': 0.0001,
153+
'GRASS_OUTPUT_TYPE_PARAMETER': 0}
154+
feedback = QgsProcessingFeedback()
155+
156+
results, ok = alg.run(parameters, context, feedback)
157+
self.assertTrue(ok)
158+
self.assertTrue(os.path.exists(temp_file))
159+
160+
# make sure that layer has correct features
161+
res = QgsVectorLayer(temp_file, 'res')
162+
self.assertTrue(res.isValid())
163+
self.assertEqual(res.featureCount(), 1)
164+
165+
QgsProject.instance().removeMapLayer(layer)
166+
167+
if __name__ == '__main__':
168+
nose2.main()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# See ../README.md for a description of the file format
2+
3+
tests:
4+
5+
# v.* modules
6+
# - algorithm: grass7:r.plane
7+
# name: GRASS7 r.plane
8+
# params:
9+
# GRASS_REGION_PARAMETER: 344500.0,358400.0,6682800.0,6693700.0
10+
# azimuth: 125
11+
# dip: 45
12+
# easting: 351610
13+
# elevation: 50
14+
# northing: 6688312
15+
# type: 1
16+
# results:
17+
# output:
18+
# hash: a9326678c39b6f925e7f22f6e79a48217100071cc8af85d675f28462
19+
# type: rasterhash
20+

0 commit comments

Comments
 (0)