Fix processing algorithm checkvalidity reason

Fixex #19617 - Check validity algorithm returns empty reason in attribute table
This commit is contained in:
Alessandro Pasotti 2018-09-18 16:36:30 +02:00
parent 5b7e60ac45
commit 001a81bc46
3 changed files with 136 additions and 3 deletions

View File

@ -157,9 +157,6 @@ class CheckValidity(QgisAlgorithm):
if not geom.isNull() and not geom.isEmpty():
errors = list(geom.validateGeometry(method))
if errors:
# QGIS method return a summary at the end
if method == 1:
errors.pop()
valid = False
reasons = []
for error in errors:

View File

@ -143,6 +143,7 @@ ADD_PYTHON_TEST(PyQgsPointDisplacementRenderer test_qgspointdisplacementrenderer
ADD_PYTHON_TEST(PyQgsPostgresDomain test_qgspostgresdomain.py)
ADD_PYTHON_TEST(PyQgsProcessingRecentAlgorithmLog test_qgsprocessingrecentalgorithmslog.py)
ADD_PYTHON_TEST(PyQgsProcessingInPlace test_qgsprocessinginplace.py)
ADD_PYTHON_TEST(PyQgsProcessingCheckValidity test_qgsprocessing_checkvalidity.py)
ADD_PYTHON_TEST(PyQgsProjectionSelectionWidgets test_qgsprojectionselectionwidgets.py)
ADD_PYTHON_TEST(PyQgsProjectMetadata test_qgsprojectmetadata.py)
ADD_PYTHON_TEST(PyQgsRange test_qgsrange.py)

View File

@ -0,0 +1,135 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for Processing CheckValidity algorithm.
.. note:: 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__ = 'Alessandro Pasotti'
__date__ = '2018-09'
__copyright__ = 'Copyright 2018, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
from qgis.PyQt.QtCore import QCoreApplication, QVariant
from qgis.core import (
QgsFeature,
QgsGeometry,
QgsApplication,
QgsMemoryProviderUtils,
QgsWkbTypes,
QgsField,
QgsFields,
QgsProcessingContext,
QgsProcessingFeedback,
QgsCoordinateReferenceSystem,
QgsProject,
QgsProcessingException,
QgsProcessingUtils,
QgsSettings
)
from processing.core.Processing import Processing
from processing.gui.AlgorithmExecutor import execute
from qgis.testing import start_app, unittest
from qgis.PyQt.QtTest import QSignalSpy
from qgis.analysis import QgsNativeAlgorithms
start_app()
class ConsoleFeedBack(QgsProcessingFeedback):
def reportError(self, error, fatalError=False):
print(error)
class TestQgsProcessingCheckValidity(unittest.TestCase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
QCoreApplication.setOrganizationName("QGIS_Test")
QCoreApplication.setOrganizationDomain(
"QGIS_TestPyQgsProcessingCheckValidity.com")
QCoreApplication.setApplicationName(
"QGIS_TestPyQgsProcessingCheckValidity")
QgsSettings().clear()
Processing.initialize()
QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms())
cls.registry = QgsApplication.instance().processingRegistry()
def _make_layer(self, layer_wkb_name):
fields = QgsFields()
wkb_type = getattr(QgsWkbTypes, layer_wkb_name)
fields.append(QgsField('int_f', QVariant.Int))
layer = QgsMemoryProviderUtils.createMemoryLayer(
'%s_layer' % layer_wkb_name, fields, wkb_type, QgsCoordinateReferenceSystem(4326))
self.assertTrue(layer.isValid())
self.assertEqual(layer.wkbType(), wkb_type)
return layer
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\nGeometry has 1 errors.'])
# 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'])
if __name__ == '__main__':
unittest.main()