Grass7AlgorithmsVectorTest.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. """
  2. ***************************************************************************
  3. Grass7AlgorithmsVectorTest.py
  4. -----------------------------
  5. Date : April 2018
  6. Copyright : (C) 2018 by Nyall Dawson
  7. Email : nyall dot dawson at gmail dot com
  8. ***************************************************************************
  9. * *
  10. * This program is free software; you can redistribute it and/or modify *
  11. * it under the terms of the GNU General Public License as published by *
  12. * the Free Software Foundation; either version 2 of the License, or *
  13. * (at your option) any later version. *
  14. * *
  15. ***************************************************************************
  16. """
  17. __author__ = 'Nyall Dawson'
  18. __date__ = 'March 2018'
  19. __copyright__ = '(C) 2018, Nyall Dawson'
  20. import AlgorithmsTestBase
  21. import nose2
  22. import shutil
  23. import os
  24. import tempfile
  25. import re
  26. from qgis.core import (QgsVectorLayer,
  27. QgsApplication,
  28. QgsFeature,
  29. QgsGeometry,
  30. QgsPointXY,
  31. QgsProcessingContext,
  32. QgsProject,
  33. QgsProcessingFeedback,
  34. QgsProcessingFeatureSourceDefinition)
  35. from qgis.testing import (
  36. start_app,
  37. unittest
  38. )
  39. from grassprovider.Grass7AlgorithmProvider import Grass7AlgorithmProvider
  40. from grassprovider.Grass7Utils import Grass7Utils
  41. testDataPath = os.path.join(os.path.dirname(__file__), 'testdata')
  42. class TestGrass7AlgorithmsVectorTest(unittest.TestCase, AlgorithmsTestBase.AlgorithmsTest):
  43. @classmethod
  44. def setUpClass(cls):
  45. start_app()
  46. cls.provider = Grass7AlgorithmProvider()
  47. QgsApplication.processingRegistry().addProvider(cls.provider)
  48. cls.cleanup_paths = []
  49. cls.temp_dir = tempfile.mkdtemp()
  50. cls.cleanup_paths.append(cls.temp_dir)
  51. assert Grass7Utils.installedVersion()
  52. @classmethod
  53. def tearDownClass(cls):
  54. QgsApplication.processingRegistry().removeProvider(cls.provider)
  55. for path in cls.cleanup_paths:
  56. shutil.rmtree(path)
  57. def test_definition_file(self):
  58. return 'grass7_algorithms_vector_tests.yaml'
  59. def testMemoryLayerInput(self):
  60. # create a memory layer and add to project and context
  61. layer = QgsVectorLayer("Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer",
  62. "testmem", "memory")
  63. self.assertTrue(layer.isValid())
  64. pr = layer.dataProvider()
  65. f = QgsFeature()
  66. f.setAttributes(["test", 123])
  67. f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(100, 200)))
  68. f2 = QgsFeature()
  69. f2.setAttributes(["test2", 457])
  70. f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(110, 200)))
  71. self.assertTrue(pr.addFeatures([f, f2]))
  72. self.assertEqual(layer.featureCount(), 2)
  73. QgsProject.instance().addMapLayer(layer)
  74. context = QgsProcessingContext()
  75. context.setProject(QgsProject.instance())
  76. alg = QgsApplication.processingRegistry().createAlgorithmById('grass7:v.buffer')
  77. self.assertIsNotNone(alg)
  78. temp_file = os.path.join(self.temp_dir, 'grass_output.shp')
  79. parameters = {'input': 'testmem',
  80. 'cats': '',
  81. 'where': '',
  82. 'type': [0, 1, 4],
  83. 'distance': 1,
  84. 'minordistance': None,
  85. 'angle': 0,
  86. 'column': None,
  87. 'scale': 1,
  88. 'tolerance': 0.01,
  89. '-s': False,
  90. '-c': False,
  91. '-t': False,
  92. 'output': temp_file,
  93. 'GRASS_REGION_PARAMETER': None,
  94. 'GRASS_SNAP_TOLERANCE_PARAMETER': -1,
  95. 'GRASS_MIN_AREA_PARAMETER': 0.0001,
  96. 'GRASS_OUTPUT_TYPE_PARAMETER': 0,
  97. 'GRASS_VECTOR_DSCO': '',
  98. 'GRASS_VECTOR_LCO': ''}
  99. feedback = QgsProcessingFeedback()
  100. results, ok = alg.run(parameters, context, feedback)
  101. self.assertTrue(ok)
  102. self.assertTrue(os.path.exists(temp_file))
  103. # make sure that layer has correct features
  104. res = QgsVectorLayer(temp_file, 'res')
  105. self.assertTrue(res.isValid())
  106. self.assertEqual(res.featureCount(), 2)
  107. QgsProject.instance().removeMapLayer(layer)
  108. def testFeatureSourceInput(self):
  109. # create a memory layer and add to project and context
  110. layer = QgsVectorLayer("Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer",
  111. "testmem", "memory")
  112. self.assertTrue(layer.isValid())
  113. pr = layer.dataProvider()
  114. f = QgsFeature()
  115. f.setAttributes(["test", 123])
  116. f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(100, 200)))
  117. f2 = QgsFeature()
  118. f2.setAttributes(["test2", 457])
  119. f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(110, 200)))
  120. self.assertTrue(pr.addFeatures([f, f2]))
  121. self.assertEqual(layer.featureCount(), 2)
  122. # select first feature
  123. layer.selectByIds([next(layer.getFeatures()).id()])
  124. self.assertEqual(len(layer.selectedFeatureIds()), 1)
  125. QgsProject.instance().addMapLayer(layer)
  126. context = QgsProcessingContext()
  127. context.setProject(QgsProject.instance())
  128. alg = QgsApplication.processingRegistry().createAlgorithmById('grass7:v.buffer')
  129. self.assertIsNotNone(alg)
  130. temp_file = os.path.join(self.temp_dir, 'grass_output_sel.shp')
  131. parameters = {'input': QgsProcessingFeatureSourceDefinition('testmem', True),
  132. 'cats': '',
  133. 'where': '',
  134. 'type': [0, 1, 4],
  135. 'distance': 1,
  136. 'minordistance': None,
  137. 'angle': 0,
  138. 'column': None,
  139. 'scale': 1,
  140. 'tolerance': 0.01,
  141. '-s': False,
  142. '-c': False,
  143. '-t': False,
  144. 'output': temp_file,
  145. 'GRASS_REGION_PARAMETER': None,
  146. 'GRASS_SNAP_TOLERANCE_PARAMETER': -1,
  147. 'GRASS_MIN_AREA_PARAMETER': 0.0001,
  148. 'GRASS_OUTPUT_TYPE_PARAMETER': 0,
  149. 'GRASS_VECTOR_DSCO': '',
  150. 'GRASS_VECTOR_LCO': ''}
  151. feedback = QgsProcessingFeedback()
  152. results, ok = alg.run(parameters, context, feedback)
  153. self.assertTrue(ok)
  154. self.assertTrue(os.path.exists(temp_file))
  155. # make sure that layer has correct features
  156. res = QgsVectorLayer(temp_file, 'res')
  157. self.assertTrue(res.isValid())
  158. self.assertEqual(res.featureCount(), 1)
  159. QgsProject.instance().removeMapLayer(layer)
  160. def testOutputToGeopackage(self):
  161. # create a memory layer and add to project and context
  162. layer = QgsVectorLayer("Point?crs=epsg:3857&field=fldtxt:string&field=fldint:integer",
  163. "testmem", "memory")
  164. self.assertTrue(layer.isValid())
  165. pr = layer.dataProvider()
  166. f = QgsFeature()
  167. f.setAttributes(["test", 123])
  168. f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(100, 200)))
  169. f2 = QgsFeature()
  170. f2.setAttributes(["test2", 457])
  171. f2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(110, 200)))
  172. self.assertTrue(pr.addFeatures([f, f2]))
  173. self.assertEqual(layer.featureCount(), 2)
  174. QgsProject.instance().addMapLayer(layer)
  175. context = QgsProcessingContext()
  176. context.setProject(QgsProject.instance())
  177. alg = QgsApplication.processingRegistry().createAlgorithmById('grass7:v.buffer')
  178. self.assertIsNotNone(alg)
  179. temp_file = os.path.join(self.temp_dir, 'grass_output.gpkg')
  180. parameters = {'input': 'testmem',
  181. 'cats': '',
  182. 'where': '',
  183. 'type': [0, 1, 4],
  184. 'distance': 1,
  185. 'minordistance': None,
  186. 'angle': 0,
  187. 'column': None,
  188. 'scale': 1,
  189. 'tolerance': 0.01,
  190. '-s': False,
  191. '-c': False,
  192. '-t': False,
  193. 'output': temp_file,
  194. 'GRASS_REGION_PARAMETER': None,
  195. 'GRASS_SNAP_TOLERANCE_PARAMETER': -1,
  196. 'GRASS_MIN_AREA_PARAMETER': 0.0001,
  197. 'GRASS_OUTPUT_TYPE_PARAMETER': 0,
  198. 'GRASS_VECTOR_DSCO': '',
  199. 'GRASS_VECTOR_LCO': ''}
  200. feedback = QgsProcessingFeedback()
  201. results, ok = alg.run(parameters, context, feedback)
  202. self.assertTrue(ok)
  203. self.assertTrue(os.path.exists(temp_file))
  204. # make sure that layer has correct features
  205. res = QgsVectorLayer(temp_file, 'res')
  206. self.assertTrue(res.isValid())
  207. self.assertEqual(res.featureCount(), 2)
  208. QgsProject.instance().removeMapLayer(layer)
  209. def testVectorLayerInput(self):
  210. context = QgsProcessingContext()
  211. alg = QgsApplication.processingRegistry().createAlgorithmById('grass7:v.buffer')
  212. self.assertIsNotNone(alg)
  213. self.assertFalse(alg.commands)
  214. def get_command(alg):
  215. command = alg.commands[-1]
  216. command = re.sub(r'output=".*?"', 'output="###"', command)
  217. command = command.replace(testDataPath, 'testdata')
  218. return command
  219. # GML source
  220. source = os.path.join(testDataPath, 'points.gml')
  221. vl = QgsVectorLayer(source)
  222. self.assertTrue(vl.isValid())
  223. alg.loadVectorLayer('test_layer', vl, context, external=False)
  224. self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/points.gml" output="###" --overwrite -o')
  225. # try with external -- not support for GML, so should fall back to v.in.ogr
  226. alg.loadVectorLayer('test_layer', vl, context, external=True)
  227. self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/points.gml" output="###" --overwrite -o')
  228. # SHP source
  229. source = os.path.join(testDataPath, 'lines_z.shp')
  230. vl = QgsVectorLayer(source)
  231. self.assertTrue(vl.isValid())
  232. alg.loadVectorLayer('test_layer', vl, context, external=False)
  233. self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/lines_z.shp" output="###" --overwrite -o')
  234. # try with external -- should work for shapefile
  235. alg.loadVectorLayer('test_layer', vl, context, external=True)
  236. self.assertEqual(get_command(alg), 'v.external input="testdata/lines_z.shp" output="###" --overwrite -o')
  237. # GPKG source
  238. source = os.path.join(testDataPath, 'pol.gpkg')
  239. vl = QgsVectorLayer(source + '|layername=pol2')
  240. self.assertTrue(vl.isValid())
  241. alg.loadVectorLayer('test_layer', vl, context, external=False)
  242. self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" layer="pol2" output="###" --overwrite -o')
  243. # try with external -- should work for Geopackage (although grass itself tends to crash here!)
  244. alg.loadVectorLayer('test_layer', vl, context, external=True)
  245. self.assertEqual(get_command(alg), 'v.external input="testdata/pol.gpkg" layer="pol2" output="###" --overwrite -o')
  246. # different layer
  247. source = os.path.join(testDataPath, 'pol.gpkg')
  248. vl = QgsVectorLayer(source + '|layername=pol3')
  249. self.assertTrue(vl.isValid())
  250. alg.loadVectorLayer('test_layer', vl, context, external=False)
  251. self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o')
  252. alg.loadVectorLayer('test_layer', vl, context, external=True)
  253. self.assertEqual(get_command(alg), 'v.external input="testdata/pol.gpkg" layer="pol3" output="###" --overwrite -o')
  254. # GPKG no layer: you get what you get and you don't get upset
  255. source = os.path.join(testDataPath, 'pol.gpkg')
  256. vl = QgsVectorLayer(source)
  257. self.assertTrue(vl.isValid())
  258. alg.loadVectorLayer('test_layer', vl, context, external=False)
  259. self.assertEqual(get_command(alg), 'v.in.ogr min_area=None snap=None input="testdata/pol.gpkg" output="###" --overwrite -o')
  260. alg.loadVectorLayer('test_layer', vl, context, external=True)
  261. self.assertEqual(get_command(alg), 'v.external input="testdata/pol.gpkg" output="###" --overwrite -o')
  262. if __name__ == '__main__':
  263. nose2.main()