Skip to content

Commit

Permalink
[processing][grass] Fix grass vector algs don't work with memory layers
Browse files Browse the repository at this point in the history
Fixes broken grass algs inside models (fixes #18662)

(cherry-picked from 8ba762a)
  • Loading branch information
nyalldawson committed Apr 9, 2018
1 parent b0eb85d commit a675311
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 3 deletions.
1 change: 1 addition & 0 deletions .ci/travis/linux/blacklist.txt
Expand Up @@ -6,6 +6,7 @@ qgis_composermapgridtest
qgis_composerutils
ProcessingGrass7AlgorithmsImageryTest
ProcessingGrass7AlgorithmsRasterTest
ProcessingGrass7AlgorithmsVectorTest
PyQgsAppStartup

# temporary during processing refactoring
Expand Down
16 changes: 13 additions & 3 deletions python/plugins/processing/algs/grass7/Grass7Algorithm.py
Expand Up @@ -60,7 +60,8 @@
QgsProcessingParameterFile,
QgsProcessingParameterFolderDestination,
QgsProcessingOutputHtml,
QgsProcessingUtils)
QgsProcessingUtils,
QgsVectorLayer)
from qgis.utils import iface

from processing.core.ProcessingConfig import ProcessingConfig
Expand Down Expand Up @@ -761,7 +762,17 @@ def loadVectorLayerFromParameter(self, name, parameters, context, feedback, exte
:param external: use v.external (v.in.ogr if False).
"""
layer = self.parameterAsVectorLayer(parameters, name, context)
self.loadVectorLayer(name, layer, external)
if layer is None or layer.dataProvider().name() != 'ogr':
# 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,
QgsVectorFileWriter.supportedFormatExtensions(),
feedback=feedback)
ogr_layer = QgsVectorLayer(path, '', 'ogr')
self.loadVectorLayer(name, ogr_layer, external)
else:
# already an ogr layer source
self.loadVectorLayer(name, layer, external)

def loadVectorLayer(self, name, layer, external=False):
"""
Expand All @@ -771,7 +782,6 @@ def loadVectorLayer(self, name, layer, external=False):
:param layer: QgsMapLayer for the vector layer.
:param external: use v.external (v.in.ogr if False).
"""
# TODO: support selections
# TODO: support multiple input formats
if external is None:
external = ProcessingConfig.getSetting(
Expand Down
1 change: 1 addition & 0 deletions python/plugins/processing/tests/CMakeLists.txt
Expand Up @@ -13,5 +13,6 @@ IF(ENABLE_TESTS)
ADD_PYTHON_TEST(ProcessingGdalAlgorithmsTest GdalAlgorithmsTest.py)
ADD_PYTHON_TEST(ProcessingGrass7AlgorithmsImageryTest Grass7AlgorithmsImageryTest.py)
ADD_PYTHON_TEST(ProcessingGrass7AlgorithmsRasterTest Grass7AlgorithmsRasterTest.py)
ADD_PYTHON_TEST(ProcessingGrass7AlgorithmsVectorTest Grass7AlgorithmsVectorTest.py)
ADD_PYTHON_TEST(ProcessingSagaAlgorithmsTest SagaAlgorithmsTest.py)
ENDIF(ENABLE_TESTS)
168 changes: 168 additions & 0 deletions python/plugins/processing/tests/Grass7AlgorithmsVectorTest.py
@@ -0,0 +1,168 @@
# -*- coding: utf-8 -*-

"""
***************************************************************************
Grass7AlgorithmsVectorTest.py
-----------------------------
Date : April 2018
Copyright : (C) 2018 by Nyall Dawson
Email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""

__author__ = 'Nyall Dawson'
__date__ = 'March 2018'
__copyright__ = '(C) 2018, Nyall Dawson'

# This will get replaced with a git SHA1 when you do a git archive

__revision__ = ':%H$'

import AlgorithmsTestBase

import nose2
import shutil
import os

from qgis.core import (QgsVectorLayer,
QgsApplication,
QgsFeature,
QgsGeometry,
QgsPointXY,
QgsProcessingContext,
QgsProject,
QgsProcessingFeedback,
QgsProcessingFeatureSourceDefinition)
from qgis.testing import (
start_app,
unittest
)
from processing.algs.grass7.Grass7Utils import Grass7Utils


class TestGrass7AlgorithmsVectorTest(unittest.TestCase, AlgorithmsTestBase.AlgorithmsTest):

@classmethod
def setUpClass(cls):
start_app()
from processing.core.Processing import Processing
Processing.initialize()
cls.cleanup_paths = []

assert Grass7Utils.installedVersion()

@classmethod
def tearDownClass(cls):
from processing.core.Processing import Processing
Processing.deinitialize()
for path in cls.cleanup_paths:
shutil.rmtree(path)

def test_definition_file(self):
return 'grass7_algorithms_vector_tests.yaml'

def testMemoryLayerInput(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('grass7:v.buffer')
self.assertIsNotNone(alg)
temp_file = '/tmp/grass_output.shp'
parameters ={'input':'testmem',
'type':[0,1,4],
'distance':1,
'angle':0,
'scale':1,
'tolerance':0.01,
'-s':False,
'-c':False,
'-t':False,
'output':temp_file,
'GRASS_SNAP_TOLERANCE_PARAMETER':-1,'GRASS_MIN_AREA_PARAMETER':0.0001,'GRASS_OUTPUT_TYPE_PARAMETER':0}
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 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 = '/tmp/grass_output.shp'
parameters = {'input': QgsProcessingFeatureSourceDefinition('testmem', True),
'type': [0, 1, 4],
'distance': 1,
'angle': 0,
'scale': 1,
'tolerance': 0.01,
'-s': False,
'-c': False,
'-t': False,
'output': temp_file,
'GRASS_SNAP_TOLERANCE_PARAMETER': -1, 'GRASS_MIN_AREA_PARAMETER': 0.0001,
'GRASS_OUTPUT_TYPE_PARAMETER': 0}
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)

if __name__ == '__main__':
nose2.main()
@@ -0,0 +1,20 @@
# See ../README.md for a description of the file format

tests:

# v.* modules
# - algorithm: grass7:r.plane
# name: GRASS7 r.plane
# params:
# GRASS_REGION_PARAMETER: 344500.0,358400.0,6682800.0,6693700.0
# azimuth: 125
# dip: 45
# easting: 351610
# elevation: 50
# northing: 6688312
# type: 1
# results:
# output:
# hash: a9326678c39b6f925e7f22f6e79a48217100071cc8af85d675f28462
# type: rasterhash

0 comments on commit a675311

Please sign in to comment.