mirror of
				https://github.com/qgis/QGIS.git
				synced 2025-10-31 00:06:02 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			476 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			476 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """
 | |
| ***************************************************************************
 | |
|     ParametersTest
 | |
|     ---------------------
 | |
|     Date                 : August 2017
 | |
|     Copyright            : (C) 2017 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__ = "August 2017"
 | |
| __copyright__ = "(C) 2017, Nyall Dawson"
 | |
| 
 | |
| import os
 | |
| import unittest
 | |
| from qgis.testing import start_app, QgisTestCase
 | |
| from qgis.core import (
 | |
|     QgsApplication,
 | |
|     QgsCoordinateReferenceSystem,
 | |
|     QgsProcessingParameterMatrix,
 | |
|     QgsProcessingOutputLayerDefinition,
 | |
|     QgsProcessingParameterFeatureSink,
 | |
|     QgsProcessingParameterFileDestination,
 | |
|     QgsProcessingParameterFolderDestination,
 | |
|     QgsProcessingParameterVectorDestination,
 | |
|     QgsProcessingParameterRasterDestination,
 | |
|     QgsProcessingParameterRange,
 | |
|     QgsFeature,
 | |
|     QgsProcessingModelAlgorithm,
 | |
|     QgsUnitTypes,
 | |
|     QgsProject,
 | |
| )
 | |
| from qgis.analysis import QgsNativeAlgorithms
 | |
| 
 | |
| from processing.gui.AlgorithmDialog import AlgorithmDialog
 | |
| from processing.gui.BatchAlgorithmDialog import BatchAlgorithmDialog
 | |
| from processing.modeler.ModelerParametersDialog import ModelerParametersDialog
 | |
| from processing.gui.wrappers import (
 | |
|     BandWidgetWrapper,
 | |
|     BooleanWidgetWrapper,
 | |
|     CrsWidgetWrapper,
 | |
|     DistanceWidgetWrapper,
 | |
|     EnumWidgetWrapper,
 | |
|     ExpressionWidgetWrapper,
 | |
|     ExtentWidgetWrapper,
 | |
|     FeatureSourceWidgetWrapper,
 | |
|     FileWidgetWrapper,
 | |
|     FixedTableWidgetWrapper,
 | |
|     MapLayerWidgetWrapper,
 | |
|     MeshWidgetWrapper,
 | |
|     MultipleLayerWidgetWrapper,
 | |
|     NumberWidgetWrapper,
 | |
|     PointWidgetWrapper,
 | |
|     ProcessingConfig,
 | |
|     QgsProcessingFeatureSourceDefinition,
 | |
|     QgsProcessingParameterBand,
 | |
|     QgsProcessingParameterBoolean,
 | |
|     QgsProcessingParameterCrs,
 | |
|     QgsProcessingParameterDistance,
 | |
|     QgsProcessingParameterDuration,
 | |
|     QgsProcessingParameterEnum,
 | |
|     QgsProcessingParameterExpression,
 | |
|     QgsProcessingParameterExtent,
 | |
|     QgsProcessingParameterFeatureSource,
 | |
|     QgsProcessingParameterField,
 | |
|     QgsProcessingParameterFile,
 | |
|     QgsProcessingParameterMapLayer,
 | |
|     QgsProcessingParameterMeshLayer,
 | |
|     QgsProcessingParameterMultipleLayers,
 | |
|     QgsProcessingParameterNumber,
 | |
|     QgsProcessingParameterPoint,
 | |
|     QgsProcessingParameterRasterLayer,
 | |
|     QgsProcessingParameterString,
 | |
|     QgsProcessingParameterVectorLayer,
 | |
|     QgsVectorLayer,
 | |
|     RangeWidgetWrapper,
 | |
|     RasterWidgetWrapper,
 | |
|     StringWidgetWrapper,
 | |
|     TableFieldWidgetWrapper,
 | |
|     VectorLayerWidgetWrapper,
 | |
|     WidgetWrapperFactory,
 | |
| )
 | |
| 
 | |
| start_app()
 | |
| QgsApplication.processingRegistry().addProvider(QgsNativeAlgorithms())
 | |
| 
 | |
| testDataPath = os.path.join(os.path.dirname(__file__), "testdata")
 | |
| 
 | |
| 
 | |
| class AlgorithmDialogTest(QgisTestCase):
 | |
| 
 | |
|     def testCreation(self):
 | |
|         alg = QgsApplication.processingRegistry().createAlgorithmById(
 | |
|             "native:centroids"
 | |
|         )
 | |
|         a = AlgorithmDialog(alg)
 | |
|         self.assertEqual(a.mainWidget().algorithm(), alg)
 | |
| 
 | |
| 
 | |
| class WrappersTest(QgisTestCase):
 | |
| 
 | |
|     @classmethod
 | |
|     def setUpClass(cls):
 | |
|         super().setUpClass()
 | |
|         ProcessingConfig.initialize()
 | |
| 
 | |
|     def checkConstructWrapper(self, param, expected_wrapper_class):
 | |
|         alg = QgsApplication.processingRegistry().createAlgorithmById(
 | |
|             "native:centroids"
 | |
|         )
 | |
| 
 | |
|         # algorithm dialog
 | |
|         dlg = AlgorithmDialog(alg)
 | |
|         wrapper = WidgetWrapperFactory.create_wrapper_from_class(param, dlg)
 | |
|         self.assertIsNotNone(wrapper)
 | |
|         self.assertIsInstance(wrapper, expected_wrapper_class)
 | |
|         self.assertEqual(wrapper.dialog, dlg)
 | |
|         self.assertIsNotNone(wrapper.widget)
 | |
|         wrapper.widget.deleteLater()
 | |
|         del wrapper.widget
 | |
|         del wrapper
 | |
| 
 | |
|         alg = QgsApplication.processingRegistry().createAlgorithmById(
 | |
|             "native:centroids"
 | |
|         )
 | |
|         # batch dialog
 | |
|         dlg = BatchAlgorithmDialog(alg)
 | |
|         wrapper = WidgetWrapperFactory.create_wrapper_from_class(param, dlg)
 | |
|         self.assertIsNotNone(wrapper)
 | |
|         self.assertIsInstance(wrapper, expected_wrapper_class)
 | |
|         self.assertEqual(wrapper.dialog, dlg)
 | |
|         self.assertIsNotNone(wrapper.widget)
 | |
| 
 | |
|         alg = QgsApplication.processingRegistry().createAlgorithmById(
 | |
|             "native:centroids"
 | |
|         )
 | |
| 
 | |
|         # modeler dialog
 | |
|         model = QgsProcessingModelAlgorithm()
 | |
|         dlg = ModelerParametersDialog(alg, model)
 | |
|         wrapper = WidgetWrapperFactory.create_wrapper_from_class(param, dlg)
 | |
|         self.assertIsNotNone(wrapper)
 | |
|         self.assertIsInstance(wrapper, expected_wrapper_class)
 | |
|         self.assertEqual(wrapper.dialog, dlg)
 | |
|         self.assertIsNotNone(wrapper.widget)
 | |
| 
 | |
|         wrapper.widget.deleteLater()
 | |
|         del wrapper.widget
 | |
| 
 | |
|     def testBoolean(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterBoolean("test"), BooleanWidgetWrapper
 | |
|         )
 | |
| 
 | |
|     def testCrs(self):
 | |
|         self.checkConstructWrapper(QgsProcessingParameterCrs("test"), CrsWidgetWrapper)
 | |
| 
 | |
|     def testExtent(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterExtent("test"), ExtentWidgetWrapper
 | |
|         )
 | |
| 
 | |
|     def testPoint(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterPoint("test"), PointWidgetWrapper
 | |
|         )
 | |
| 
 | |
|     def testFile(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterFile("test"), FileWidgetWrapper
 | |
|         )
 | |
| 
 | |
|     def testMultiInput(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterMultipleLayers("test"), MultipleLayerWidgetWrapper
 | |
|         )
 | |
| 
 | |
|     def testRasterInput(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterRasterLayer("test"), RasterWidgetWrapper
 | |
|         )
 | |
| 
 | |
|     def testEnum(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterEnum("test"), EnumWidgetWrapper
 | |
|         )
 | |
| 
 | |
|     def testString(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterString("test"), StringWidgetWrapper
 | |
|         )
 | |
| 
 | |
|     def testExpression(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterExpression("test"), ExpressionWidgetWrapper
 | |
|         )
 | |
| 
 | |
|     def testVector(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterVectorLayer("test"), VectorLayerWidgetWrapper
 | |
|         )
 | |
| 
 | |
|     def testField(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterField("test"), TableFieldWidgetWrapper
 | |
|         )
 | |
| 
 | |
|     def testSource(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterFeatureSource("test"), FeatureSourceWidgetWrapper
 | |
|         )
 | |
| 
 | |
|         # dummy layer
 | |
|         layer = QgsVectorLayer("Point", "test", "memory")
 | |
|         # need at least one feature in order to have a selection
 | |
|         layer.dataProvider().addFeature(QgsFeature())
 | |
|         layer.selectAll()
 | |
| 
 | |
|         self.assertTrue(layer.isValid())
 | |
|         QgsProject.instance().addMapLayer(layer)
 | |
| 
 | |
|         alg = QgsApplication.processingRegistry().createAlgorithmById(
 | |
|             "native:centroids"
 | |
|         )
 | |
|         dlg = AlgorithmDialog(alg)
 | |
|         param = QgsProcessingParameterFeatureSource("test")
 | |
|         wrapper = FeatureSourceWidgetWrapper(param, dlg)
 | |
|         widget = wrapper.createWidget()
 | |
| 
 | |
|         # check layer value
 | |
|         widget.show()
 | |
|         wrapper.setValue(layer.id())
 | |
|         self.assertEqual(wrapper.value(), layer.id())
 | |
| 
 | |
|         # check selected only - expect a QgsProcessingFeatureSourceDefinition
 | |
|         wrapper.setValue(QgsProcessingFeatureSourceDefinition(layer.id(), True))
 | |
|         value = wrapper.value()
 | |
|         self.assertIsInstance(value, QgsProcessingFeatureSourceDefinition)
 | |
|         self.assertTrue(value.selectedFeaturesOnly)
 | |
|         self.assertEqual(value.source.staticValue(), layer.id())
 | |
| 
 | |
|         # NOT selected only, expect a direct layer id or source value
 | |
|         wrapper.setValue(QgsProcessingFeatureSourceDefinition(layer.id(), False))
 | |
|         value = wrapper.value()
 | |
|         self.assertEqual(value, layer.id())
 | |
| 
 | |
|         # with non-project layer
 | |
|         wrapper.setValue("/home/my_layer.shp")
 | |
|         value = wrapper.value()
 | |
|         self.assertEqual(value, "/home/my_layer.shp")
 | |
| 
 | |
|         widget.deleteLater()
 | |
|         del widget
 | |
| 
 | |
|     def testRange(self):
 | |
|         # minimal test to check if wrapper generate GUI for each processign context
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterRange("test"), RangeWidgetWrapper
 | |
|         )
 | |
| 
 | |
|         alg = QgsApplication.processingRegistry().createAlgorithmById(
 | |
|             "native:centroids"
 | |
|         )
 | |
|         dlg = AlgorithmDialog(alg)
 | |
|         param = QgsProcessingParameterRange(
 | |
|             name="test",
 | |
|             description="test",
 | |
|             type=QgsProcessingParameterNumber.Type.Double,
 | |
|             defaultValue="0.0,100.0",
 | |
|         )
 | |
| 
 | |
|         wrapper = RangeWidgetWrapper(param, dlg)
 | |
|         widget = wrapper.createWidget()
 | |
| 
 | |
|         # range values check
 | |
| 
 | |
|         # check initial value
 | |
|         self.assertEqual(widget.getValue(), "0.0,100.0")
 | |
|         # check set/get
 | |
|         widget.setValue("100.0,200.0")
 | |
|         self.assertEqual(widget.getValue(), "100.0,200.0")
 | |
|         # check that min/max are mutually adapted
 | |
|         widget.setValue("200.0,100.0")
 | |
|         self.assertEqual(widget.getValue(), "100.0,100.0")
 | |
|         widget.spnMax.setValue(50)
 | |
|         self.assertEqual(widget.getValue(), "50.0,50.0")
 | |
|         widget.spnMin.setValue(100)
 | |
|         self.assertEqual(widget.getValue(), "100.0,100.0")
 | |
| 
 | |
|         # check for integers
 | |
|         param = QgsProcessingParameterRange(
 | |
|             name="test",
 | |
|             description="test",
 | |
|             type=QgsProcessingParameterNumber.Type.Integer,
 | |
|             defaultValue="0.1,100.1",
 | |
|         )
 | |
| 
 | |
|         wrapper = RangeWidgetWrapper(param, dlg)
 | |
|         widget = wrapper.createWidget()
 | |
| 
 | |
|         # range values check
 | |
| 
 | |
|         # check initial value
 | |
|         self.assertEqual(widget.getValue(), "0.0,100.0")
 | |
|         # check rounding
 | |
|         widget.setValue("100.1,200.1")
 | |
|         self.assertEqual(widget.getValue(), "100.0,200.0")
 | |
|         widget.setValue("100.6,200.6")
 | |
|         self.assertEqual(widget.getValue(), "101.0,201.0")
 | |
|         # check set/get
 | |
|         widget.setValue("100.1,200.1")
 | |
|         self.assertEqual(widget.getValue(), "100.0,200.0")
 | |
|         # check that min/max are mutually adapted
 | |
|         widget.setValue("200.1,100.1")
 | |
|         self.assertEqual(widget.getValue(), "100.0,100.0")
 | |
|         widget.spnMax.setValue(50.1)
 | |
|         self.assertEqual(widget.getValue(), "50.0,50.0")
 | |
|         widget.spnMin.setValue(100.1)
 | |
|         self.assertEqual(widget.getValue(), "100.0,100.0")
 | |
| 
 | |
|     def testMapLayer(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterMapLayer("test"), MapLayerWidgetWrapper
 | |
|         )
 | |
| 
 | |
|     def testMeshLayer(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterMeshLayer("test"), MeshWidgetWrapper
 | |
|         )
 | |
| 
 | |
|     def testDistance(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterDistance("test"), DistanceWidgetWrapper
 | |
|         )
 | |
| 
 | |
|         alg = QgsApplication.processingRegistry().createAlgorithmById(
 | |
|             "native:centroids"
 | |
|         )
 | |
|         dlg = AlgorithmDialog(alg)
 | |
|         param = QgsProcessingParameterDistance("test")
 | |
|         wrapper = DistanceWidgetWrapper(param, dlg)
 | |
|         widget = wrapper.createWidget()
 | |
| 
 | |
|         # test units
 | |
|         widget.show()
 | |
| 
 | |
|         # crs values
 | |
|         widget.setUnitParameterValue("EPSG:3111")
 | |
|         self.assertEqual(widget.label.text(), "meters")
 | |
|         self.assertFalse(widget.warning_label.isVisible())
 | |
|         self.assertTrue(widget.units_combo.isVisible())
 | |
|         self.assertFalse(widget.label.isVisible())
 | |
|         self.assertEqual(
 | |
|             widget.units_combo.currentData(), QgsUnitTypes.DistanceUnit.DistanceMeters
 | |
|         )
 | |
| 
 | |
|         widget.setUnitParameterValue("EPSG:4326")
 | |
|         self.assertEqual(widget.label.text(), "degrees")
 | |
|         self.assertTrue(widget.warning_label.isVisible())
 | |
|         self.assertFalse(widget.units_combo.isVisible())
 | |
|         self.assertTrue(widget.label.isVisible())
 | |
| 
 | |
|         widget.setUnitParameterValue(QgsCoordinateReferenceSystem("EPSG:3111"))
 | |
|         self.assertEqual(widget.label.text(), "meters")
 | |
|         self.assertFalse(widget.warning_label.isVisible())
 | |
|         self.assertTrue(widget.units_combo.isVisible())
 | |
|         self.assertFalse(widget.label.isVisible())
 | |
|         self.assertEqual(
 | |
|             widget.units_combo.currentData(), QgsUnitTypes.DistanceUnit.DistanceMeters
 | |
|         )
 | |
| 
 | |
|         widget.setUnitParameterValue(QgsCoordinateReferenceSystem("EPSG:4326"))
 | |
|         self.assertEqual(widget.label.text(), "degrees")
 | |
|         self.assertTrue(widget.warning_label.isVisible())
 | |
|         self.assertFalse(widget.units_combo.isVisible())
 | |
|         self.assertTrue(widget.label.isVisible())
 | |
| 
 | |
|         # layer values
 | |
|         vl = QgsVectorLayer("Polygon?crs=epsg:3111&field=pk:int", "vl", "memory")
 | |
|         widget.setUnitParameterValue(vl)
 | |
|         self.assertEqual(widget.label.text(), "meters")
 | |
|         self.assertFalse(widget.warning_label.isVisible())
 | |
|         self.assertTrue(widget.units_combo.isVisible())
 | |
|         self.assertFalse(widget.label.isVisible())
 | |
|         self.assertEqual(
 | |
|             widget.units_combo.currentData(), QgsUnitTypes.DistanceUnit.DistanceMeters
 | |
|         )
 | |
| 
 | |
|         vl2 = QgsVectorLayer("Polygon?crs=epsg:4326&field=pk:int", "vl", "memory")
 | |
|         widget.setUnitParameterValue(vl2)
 | |
|         self.assertEqual(widget.label.text(), "degrees")
 | |
|         self.assertTrue(widget.warning_label.isVisible())
 | |
|         self.assertFalse(widget.units_combo.isVisible())
 | |
|         self.assertTrue(widget.label.isVisible())
 | |
| 
 | |
|         # unresolvable values
 | |
|         widget.setUnitParameterValue(vl.id())
 | |
|         self.assertEqual(widget.label.text(), "<unknown>")
 | |
|         self.assertFalse(widget.warning_label.isVisible())
 | |
|         self.assertFalse(widget.units_combo.isVisible())
 | |
|         self.assertTrue(widget.label.isVisible())
 | |
| 
 | |
|         # resolvable text value
 | |
|         QgsProject.instance().addMapLayer(vl)
 | |
|         widget.setUnitParameterValue(vl.id())
 | |
|         self.assertEqual(widget.label.text(), "meters")
 | |
|         self.assertFalse(widget.warning_label.isVisible())
 | |
|         self.assertTrue(widget.units_combo.isVisible())
 | |
|         self.assertFalse(widget.label.isVisible())
 | |
|         self.assertEqual(
 | |
|             widget.units_combo.currentData(), QgsUnitTypes.DistanceUnit.DistanceMeters
 | |
|         )
 | |
| 
 | |
|         widget.setValue(5)
 | |
|         self.assertEqual(widget.getValue(), 5)
 | |
|         widget.units_combo.setCurrentIndex(
 | |
|             widget.units_combo.findData(QgsUnitTypes.DistanceUnit.DistanceKilometers)
 | |
|         )
 | |
|         self.assertEqual(widget.getValue(), 5000)
 | |
|         widget.setValue(2)
 | |
|         self.assertEqual(widget.getValue(), 2000)
 | |
| 
 | |
|         widget.setUnitParameterValue(vl.id())
 | |
|         self.assertEqual(widget.getValue(), 2)
 | |
|         widget.setValue(5)
 | |
|         self.assertEqual(widget.getValue(), 5)
 | |
| 
 | |
|         widget.deleteLater()
 | |
| 
 | |
|     def testMatrix(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterMatrix("test"), FixedTableWidgetWrapper
 | |
|         )
 | |
| 
 | |
|         alg = QgsApplication.processingRegistry().createAlgorithmById(
 | |
|             "native:centroids"
 | |
|         )
 | |
|         dlg = AlgorithmDialog(alg)
 | |
|         param = QgsProcessingParameterMatrix(
 | |
|             "test", "test", 2, True, ["x", "y"], [["a", "b"], ["c", "d"]]
 | |
|         )
 | |
|         wrapper = FixedTableWidgetWrapper(param, dlg)
 | |
|         widget = wrapper.createWidget()
 | |
| 
 | |
|         # check that default value is initially set
 | |
|         self.assertEqual(wrapper.value(), [["a", "b"], ["c", "d"]])
 | |
| 
 | |
|         # test widget
 | |
|         widget.show()
 | |
|         wrapper.setValue([[1, 2], [3, 4]])
 | |
|         self.assertEqual(wrapper.value(), [[1, 2], [3, 4]])
 | |
| 
 | |
|         widget.deleteLater()
 | |
| 
 | |
|     def testNumber(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterNumber("test"), NumberWidgetWrapper
 | |
|         )
 | |
| 
 | |
|     def testBand(self):
 | |
|         self.checkConstructWrapper(
 | |
|             QgsProcessingParameterBand("test"), BandWidgetWrapper
 | |
|         )
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     unittest.main()
 |